• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // YUV->RGB conversion functions
11 //
12 // Author: Skal (pascal.massimino@gmail.com)
13 
14 #include "src/dsp/yuv.h"
15 
16 #include <assert.h>
17 #include <stdlib.h>
18 
19 //-----------------------------------------------------------------------------
20 // Plain-C version
21 
22 #define ROW_FUNC(FUNC_NAME, FUNC, XSTEP)                                       \
23 static void FUNC_NAME(const uint8_t* WEBP_RESTRICT y,                          \
24                       const uint8_t* WEBP_RESTRICT u,                          \
25                       const uint8_t* WEBP_RESTRICT v,                          \
26                       uint8_t* WEBP_RESTRICT dst, int len) {                   \
27   const uint8_t* const end = dst + (len & ~1) * (XSTEP);                       \
28   while (dst != end) {                                                         \
29     FUNC(y[0], u[0], v[0], dst);                                               \
30     FUNC(y[1], u[0], v[0], dst + (XSTEP));                                     \
31     y += 2;                                                                    \
32     ++u;                                                                       \
33     ++v;                                                                       \
34     dst += 2 * (XSTEP);                                                        \
35   }                                                                            \
36   if (len & 1) {                                                               \
37     FUNC(y[0], u[0], v[0], dst);                                               \
38   }                                                                            \
39 }                                                                              \
40 
41 // All variants implemented.
42 ROW_FUNC(YuvToRgbRow,      VP8YuvToRgb,  3)
43 ROW_FUNC(YuvToBgrRow,      VP8YuvToBgr,  3)
44 ROW_FUNC(YuvToRgbaRow,     VP8YuvToRgba, 4)
45 ROW_FUNC(YuvToBgraRow,     VP8YuvToBgra, 4)
46 ROW_FUNC(YuvToArgbRow,     VP8YuvToArgb, 4)
47 ROW_FUNC(YuvToRgba4444Row, VP8YuvToRgba4444, 2)
48 ROW_FUNC(YuvToRgb565Row,   VP8YuvToRgb565, 2)
49 
50 #undef ROW_FUNC
51 
52 // Main call for processing a plane with a WebPSamplerRowFunc function:
WebPSamplerProcessPlane(const uint8_t * WEBP_RESTRICT y,int y_stride,const uint8_t * WEBP_RESTRICT u,const uint8_t * WEBP_RESTRICT v,int uv_stride,uint8_t * WEBP_RESTRICT dst,int dst_stride,int width,int height,WebPSamplerRowFunc func)53 void WebPSamplerProcessPlane(const uint8_t* WEBP_RESTRICT y, int y_stride,
54                              const uint8_t* WEBP_RESTRICT u,
55                              const uint8_t* WEBP_RESTRICT v, int uv_stride,
56                              uint8_t* WEBP_RESTRICT dst, int dst_stride,
57                              int width, int height, WebPSamplerRowFunc func) {
58   int j;
59   for (j = 0; j < height; ++j) {
60     func(y, u, v, dst, width);
61     y += y_stride;
62     if (j & 1) {
63       u += uv_stride;
64       v += uv_stride;
65     }
66     dst += dst_stride;
67   }
68 }
69 
70 //-----------------------------------------------------------------------------
71 // Main call
72 
73 WebPSamplerRowFunc WebPSamplers[MODE_LAST];
74 
75 extern VP8CPUInfo VP8GetCPUInfo;
76 extern void WebPInitSamplersSSE2(void);
77 extern void WebPInitSamplersSSE41(void);
78 extern void WebPInitSamplersMIPS32(void);
79 extern void WebPInitSamplersMIPSdspR2(void);
80 
WEBP_DSP_INIT_FUNC(WebPInitSamplers)81 WEBP_DSP_INIT_FUNC(WebPInitSamplers) {
82   WebPSamplers[MODE_RGB]       = YuvToRgbRow;
83   WebPSamplers[MODE_RGBA]      = YuvToRgbaRow;
84   WebPSamplers[MODE_BGR]       = YuvToBgrRow;
85   WebPSamplers[MODE_BGRA]      = YuvToBgraRow;
86   WebPSamplers[MODE_ARGB]      = YuvToArgbRow;
87   WebPSamplers[MODE_RGBA_4444] = YuvToRgba4444Row;
88   WebPSamplers[MODE_RGB_565]   = YuvToRgb565Row;
89   WebPSamplers[MODE_rgbA]      = YuvToRgbaRow;
90   WebPSamplers[MODE_bgrA]      = YuvToBgraRow;
91   WebPSamplers[MODE_Argb]      = YuvToArgbRow;
92   WebPSamplers[MODE_rgbA_4444] = YuvToRgba4444Row;
93 
94   // If defined, use CPUInfo() to overwrite some pointers with faster versions.
95   if (VP8GetCPUInfo != NULL) {
96 #if defined(WEBP_HAVE_SSE2)
97     if (VP8GetCPUInfo(kSSE2)) {
98       WebPInitSamplersSSE2();
99     }
100 #endif  // WEBP_HAVE_SSE2
101 #if defined(WEBP_HAVE_SSE41)
102     if (VP8GetCPUInfo(kSSE4_1)) {
103       WebPInitSamplersSSE41();
104     }
105 #endif  // WEBP_HAVE_SSE41
106 #if defined(WEBP_USE_MIPS32)
107     if (VP8GetCPUInfo(kMIPS32)) {
108       WebPInitSamplersMIPS32();
109     }
110 #endif  // WEBP_USE_MIPS32
111 #if defined(WEBP_USE_MIPS_DSP_R2)
112     if (VP8GetCPUInfo(kMIPSdspR2)) {
113       WebPInitSamplersMIPSdspR2();
114     }
115 #endif  // WEBP_USE_MIPS_DSP_R2
116   }
117 }
118 
119 //-----------------------------------------------------------------------------
120 // ARGB -> YUV converters
121 
ConvertARGBToY_C(const uint32_t * WEBP_RESTRICT argb,uint8_t * WEBP_RESTRICT y,int width)122 static void ConvertARGBToY_C(const uint32_t* WEBP_RESTRICT argb,
123                              uint8_t* WEBP_RESTRICT y, int width) {
124   int i;
125   for (i = 0; i < width; ++i) {
126     const uint32_t p = argb[i];
127     y[i] = VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >>  0) & 0xff,
128                      YUV_HALF);
129   }
130 }
131 
WebPConvertARGBToUV_C(const uint32_t * WEBP_RESTRICT argb,uint8_t * WEBP_RESTRICT u,uint8_t * WEBP_RESTRICT v,int src_width,int do_store)132 void WebPConvertARGBToUV_C(const uint32_t* WEBP_RESTRICT argb,
133                            uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v,
134                            int src_width, int do_store) {
135   // No rounding. Last pixel is dealt with separately.
136   const int uv_width = src_width >> 1;
137   int i;
138   for (i = 0; i < uv_width; ++i) {
139     const uint32_t v0 = argb[2 * i + 0];
140     const uint32_t v1 = argb[2 * i + 1];
141     // VP8RGBToU/V expects four accumulated pixels. Hence we need to
142     // scale r/g/b value by a factor 2. We just shift v0/v1 one bit less.
143     const int r = ((v0 >> 15) & 0x1fe) + ((v1 >> 15) & 0x1fe);
144     const int g = ((v0 >>  7) & 0x1fe) + ((v1 >>  7) & 0x1fe);
145     const int b = ((v0 <<  1) & 0x1fe) + ((v1 <<  1) & 0x1fe);
146     const int tmp_u = VP8RGBToU(r, g, b, YUV_HALF << 2);
147     const int tmp_v = VP8RGBToV(r, g, b, YUV_HALF << 2);
148     if (do_store) {
149       u[i] = tmp_u;
150       v[i] = tmp_v;
151     } else {
152       // Approximated average-of-four. But it's an acceptable diff.
153       u[i] = (u[i] + tmp_u + 1) >> 1;
154       v[i] = (v[i] + tmp_v + 1) >> 1;
155     }
156   }
157   if (src_width & 1) {       // last pixel
158     const uint32_t v0 = argb[2 * i + 0];
159     const int r = (v0 >> 14) & 0x3fc;
160     const int g = (v0 >>  6) & 0x3fc;
161     const int b = (v0 <<  2) & 0x3fc;
162     const int tmp_u = VP8RGBToU(r, g, b, YUV_HALF << 2);
163     const int tmp_v = VP8RGBToV(r, g, b, YUV_HALF << 2);
164     if (do_store) {
165       u[i] = tmp_u;
166       v[i] = tmp_v;
167     } else {
168       u[i] = (u[i] + tmp_u + 1) >> 1;
169       v[i] = (v[i] + tmp_v + 1) >> 1;
170     }
171   }
172 }
173 
174 //-----------------------------------------------------------------------------
175 
ConvertRGB24ToY_C(const uint8_t * WEBP_RESTRICT rgb,uint8_t * WEBP_RESTRICT y,int width)176 static void ConvertRGB24ToY_C(const uint8_t* WEBP_RESTRICT rgb,
177                               uint8_t* WEBP_RESTRICT y, int width) {
178   int i;
179   for (i = 0; i < width; ++i, rgb += 3) {
180     y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF);
181   }
182 }
183 
ConvertBGR24ToY_C(const uint8_t * WEBP_RESTRICT bgr,uint8_t * WEBP_RESTRICT y,int width)184 static void ConvertBGR24ToY_C(const uint8_t* WEBP_RESTRICT bgr,
185                               uint8_t* WEBP_RESTRICT y, int width) {
186   int i;
187   for (i = 0; i < width; ++i, bgr += 3) {
188     y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF);
189   }
190 }
191 
WebPConvertRGBA32ToUV_C(const uint16_t * WEBP_RESTRICT rgb,uint8_t * WEBP_RESTRICT u,uint8_t * WEBP_RESTRICT v,int width)192 void WebPConvertRGBA32ToUV_C(const uint16_t* WEBP_RESTRICT rgb,
193                              uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v,
194                              int width) {
195   int i;
196   for (i = 0; i < width; i += 1, rgb += 4) {
197     const int r = rgb[0], g = rgb[1], b = rgb[2];
198     u[i] = VP8RGBToU(r, g, b, YUV_HALF << 2);
199     v[i] = VP8RGBToV(r, g, b, YUV_HALF << 2);
200   }
201 }
202 
203 //-----------------------------------------------------------------------------
204 
205 void (*WebPConvertRGB24ToY)(const uint8_t* WEBP_RESTRICT rgb,
206                             uint8_t* WEBP_RESTRICT y, int width);
207 void (*WebPConvertBGR24ToY)(const uint8_t* WEBP_RESTRICT bgr,
208                             uint8_t* WEBP_RESTRICT y, int width);
209 void (*WebPConvertRGBA32ToUV)(const uint16_t* WEBP_RESTRICT rgb,
210                               uint8_t* WEBP_RESTRICT u,
211                               uint8_t* WEBP_RESTRICT v, int width);
212 
213 void (*WebPConvertARGBToY)(const uint32_t* WEBP_RESTRICT argb,
214                            uint8_t* WEBP_RESTRICT y, int width);
215 void (*WebPConvertARGBToUV)(const uint32_t* WEBP_RESTRICT argb,
216                             uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v,
217                             int src_width, int do_store);
218 
219 extern void WebPInitConvertARGBToYUVSSE2(void);
220 extern void WebPInitConvertARGBToYUVSSE41(void);
221 extern void WebPInitConvertARGBToYUVNEON(void);
222 
WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV)223 WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
224   WebPConvertARGBToY = ConvertARGBToY_C;
225   WebPConvertARGBToUV = WebPConvertARGBToUV_C;
226 
227   WebPConvertRGB24ToY = ConvertRGB24ToY_C;
228   WebPConvertBGR24ToY = ConvertBGR24ToY_C;
229 
230   WebPConvertRGBA32ToUV = WebPConvertRGBA32ToUV_C;
231 
232   if (VP8GetCPUInfo != NULL) {
233 #if defined(WEBP_HAVE_SSE2)
234     if (VP8GetCPUInfo(kSSE2)) {
235       WebPInitConvertARGBToYUVSSE2();
236     }
237 #endif  // WEBP_HAVE_SSE2
238 #if defined(WEBP_HAVE_SSE41)
239     if (VP8GetCPUInfo(kSSE4_1)) {
240       WebPInitConvertARGBToYUVSSE41();
241     }
242 #endif  // WEBP_HAVE_SSE41
243   }
244 
245 #if defined(WEBP_HAVE_NEON)
246   if (WEBP_NEON_OMIT_C_CODE ||
247       (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
248     WebPInitConvertARGBToYUVNEON();
249   }
250 #endif  // WEBP_HAVE_NEON
251 
252   assert(WebPConvertARGBToY != NULL);
253   assert(WebPConvertARGBToUV != NULL);
254   assert(WebPConvertRGB24ToY != NULL);
255   assert(WebPConvertBGR24ToY != NULL);
256   assert(WebPConvertRGBA32ToUV != NULL);
257 }
258