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