1 // Copyright 2011 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 // Spatial prediction using various filters
11 //
12 // Author: Urvang (urvang@google.com)
13
14 #include "src/dsp/dsp.h"
15 #include <assert.h>
16 #include <stdlib.h>
17 #include <string.h>
18
19 //------------------------------------------------------------------------------
20 // Helpful macro.
21
22 #define DCHECK(in, out) \
23 do { \
24 assert((in) != NULL); \
25 assert((out) != NULL); \
26 assert((in) != (out)); \
27 assert(width > 0); \
28 assert(height > 0); \
29 assert(stride >= width); \
30 } while (0)
31
32 #if !WEBP_NEON_OMIT_C_CODE
PredictLine_C(const uint8_t * WEBP_RESTRICT src,const uint8_t * WEBP_RESTRICT pred,uint8_t * WEBP_RESTRICT dst,int length)33 static WEBP_INLINE void PredictLine_C(const uint8_t* WEBP_RESTRICT src,
34 const uint8_t* WEBP_RESTRICT pred,
35 uint8_t* WEBP_RESTRICT dst, int length) {
36 int i;
37 for (i = 0; i < length; ++i) dst[i] = (uint8_t)(src[i] - pred[i]);
38 }
39
40 //------------------------------------------------------------------------------
41 // Horizontal filter.
42
DoHorizontalFilter_C(const uint8_t * WEBP_RESTRICT in,int width,int height,int stride,uint8_t * WEBP_RESTRICT out)43 static WEBP_INLINE void DoHorizontalFilter_C(const uint8_t* WEBP_RESTRICT in,
44 int width, int height, int stride,
45 uint8_t* WEBP_RESTRICT out) {
46 const uint8_t* preds = in;
47 int row;
48 DCHECK(in, out);
49
50 // Leftmost pixel is the same as input for topmost scanline.
51 out[0] = in[0];
52 PredictLine_C(in + 1, preds, out + 1, width - 1);
53 preds += stride;
54 in += stride;
55 out += stride;
56
57 // Filter line-by-line.
58 for (row = 1; row < height; ++row) {
59 // Leftmost pixel is predicted from above.
60 PredictLine_C(in, preds - stride, out, 1);
61 PredictLine_C(in + 1, preds, out + 1, width - 1);
62 preds += stride;
63 in += stride;
64 out += stride;
65 }
66 }
67
68 //------------------------------------------------------------------------------
69 // Vertical filter.
70
DoVerticalFilter_C(const uint8_t * WEBP_RESTRICT in,int width,int height,int stride,uint8_t * WEBP_RESTRICT out)71 static WEBP_INLINE void DoVerticalFilter_C(const uint8_t* WEBP_RESTRICT in,
72 int width, int height, int stride,
73 uint8_t* WEBP_RESTRICT out) {
74 const uint8_t* preds = in;
75 int row;
76 DCHECK(in, out);
77
78 // Very first top-left pixel is copied.
79 out[0] = in[0];
80 // Rest of top scan-line is left-predicted.
81 PredictLine_C(in + 1, preds, out + 1, width - 1);
82 in += stride;
83 out += stride;
84
85 // Filter line-by-line.
86 for (row = 1; row < height; ++row) {
87 PredictLine_C(in, preds, out, width);
88 preds += stride;
89 in += stride;
90 out += stride;
91 }
92 }
93 #endif // !WEBP_NEON_OMIT_C_CODE
94
95 //------------------------------------------------------------------------------
96 // Gradient filter.
97
GradientPredictor_C(uint8_t a,uint8_t b,uint8_t c)98 static WEBP_INLINE int GradientPredictor_C(uint8_t a, uint8_t b, uint8_t c) {
99 const int g = a + b - c;
100 return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit
101 }
102
103 #if !WEBP_NEON_OMIT_C_CODE
DoGradientFilter_C(const uint8_t * WEBP_RESTRICT in,int width,int height,int stride,uint8_t * WEBP_RESTRICT out)104 static WEBP_INLINE void DoGradientFilter_C(const uint8_t* WEBP_RESTRICT in,
105 int width, int height, int stride,
106 uint8_t* WEBP_RESTRICT out) {
107 const uint8_t* preds = in;
108 int row;
109 DCHECK(in, out);
110
111 // left prediction for top scan-line
112 out[0] = in[0];
113 PredictLine_C(in + 1, preds, out + 1, width - 1);
114 preds += stride;
115 in += stride;
116 out += stride;
117
118 // Filter line-by-line.
119 for (row = 1; row < height; ++row) {
120 int w;
121 // leftmost pixel: predict from above.
122 PredictLine_C(in, preds - stride, out, 1);
123 for (w = 1; w < width; ++w) {
124 const int pred = GradientPredictor_C(preds[w - 1],
125 preds[w - stride],
126 preds[w - stride - 1]);
127 out[w] = (uint8_t)(in[w] - pred);
128 }
129 preds += stride;
130 in += stride;
131 out += stride;
132 }
133 }
134 #endif // !WEBP_NEON_OMIT_C_CODE
135
136 #undef DCHECK
137
138 //------------------------------------------------------------------------------
139
140 #if !WEBP_NEON_OMIT_C_CODE
HorizontalFilter_C(const uint8_t * WEBP_RESTRICT data,int width,int height,int stride,uint8_t * WEBP_RESTRICT filtered_data)141 static void HorizontalFilter_C(const uint8_t* WEBP_RESTRICT data,
142 int width, int height, int stride,
143 uint8_t* WEBP_RESTRICT filtered_data) {
144 DoHorizontalFilter_C(data, width, height, stride, filtered_data);
145 }
146
VerticalFilter_C(const uint8_t * WEBP_RESTRICT data,int width,int height,int stride,uint8_t * WEBP_RESTRICT filtered_data)147 static void VerticalFilter_C(const uint8_t* WEBP_RESTRICT data,
148 int width, int height, int stride,
149 uint8_t* WEBP_RESTRICT filtered_data) {
150 DoVerticalFilter_C(data, width, height, stride, filtered_data);
151 }
152
GradientFilter_C(const uint8_t * WEBP_RESTRICT data,int width,int height,int stride,uint8_t * WEBP_RESTRICT filtered_data)153 static void GradientFilter_C(const uint8_t* WEBP_RESTRICT data,
154 int width, int height, int stride,
155 uint8_t* WEBP_RESTRICT filtered_data) {
156 DoGradientFilter_C(data, width, height, stride, filtered_data);
157 }
158 #endif // !WEBP_NEON_OMIT_C_CODE
159
160 //------------------------------------------------------------------------------
161
NoneUnfilter_C(const uint8_t * prev,const uint8_t * in,uint8_t * out,int width)162 static void NoneUnfilter_C(const uint8_t* prev, const uint8_t* in,
163 uint8_t* out, int width) {
164 (void)prev;
165 if (out != in) memcpy(out, in, width * sizeof(*out));
166 }
167
HorizontalUnfilter_C(const uint8_t * prev,const uint8_t * in,uint8_t * out,int width)168 static void HorizontalUnfilter_C(const uint8_t* prev, const uint8_t* in,
169 uint8_t* out, int width) {
170 uint8_t pred = (prev == NULL) ? 0 : prev[0];
171 int i;
172 for (i = 0; i < width; ++i) {
173 out[i] = (uint8_t)(pred + in[i]);
174 pred = out[i];
175 }
176 }
177
178 #if !WEBP_NEON_OMIT_C_CODE
VerticalUnfilter_C(const uint8_t * prev,const uint8_t * in,uint8_t * out,int width)179 static void VerticalUnfilter_C(const uint8_t* prev, const uint8_t* in,
180 uint8_t* out, int width) {
181 if (prev == NULL) {
182 HorizontalUnfilter_C(NULL, in, out, width);
183 } else {
184 int i;
185 for (i = 0; i < width; ++i) out[i] = (uint8_t)(prev[i] + in[i]);
186 }
187 }
188 #endif // !WEBP_NEON_OMIT_C_CODE
189
GradientUnfilter_C(const uint8_t * prev,const uint8_t * in,uint8_t * out,int width)190 static void GradientUnfilter_C(const uint8_t* prev, const uint8_t* in,
191 uint8_t* out, int width) {
192 if (prev == NULL) {
193 HorizontalUnfilter_C(NULL, in, out, width);
194 } else {
195 uint8_t top = prev[0], top_left = top, left = top;
196 int i;
197 for (i = 0; i < width; ++i) {
198 top = prev[i]; // need to read this first, in case prev==out
199 left = (uint8_t)(in[i] + GradientPredictor_C(left, top, top_left));
200 top_left = top;
201 out[i] = left;
202 }
203 }
204 }
205
206 //------------------------------------------------------------------------------
207 // Init function
208
209 WebPFilterFunc WebPFilters[WEBP_FILTER_LAST];
210 WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST];
211
212 extern VP8CPUInfo VP8GetCPUInfo;
213 extern void VP8FiltersInitMIPSdspR2(void);
214 extern void VP8FiltersInitMSA(void);
215 extern void VP8FiltersInitNEON(void);
216 extern void VP8FiltersInitSSE2(void);
217
WEBP_DSP_INIT_FUNC(VP8FiltersInit)218 WEBP_DSP_INIT_FUNC(VP8FiltersInit) {
219 WebPUnfilters[WEBP_FILTER_NONE] = NoneUnfilter_C;
220 #if !WEBP_NEON_OMIT_C_CODE
221 WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_C;
222 WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_C;
223 #endif
224 WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter_C;
225
226 WebPFilters[WEBP_FILTER_NONE] = NULL;
227 #if !WEBP_NEON_OMIT_C_CODE
228 WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_C;
229 WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_C;
230 WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_C;
231 #endif
232
233 if (VP8GetCPUInfo != NULL) {
234 #if defined(WEBP_HAVE_SSE2)
235 if (VP8GetCPUInfo(kSSE2)) {
236 VP8FiltersInitSSE2();
237 }
238 #endif
239 #if defined(WEBP_USE_MIPS_DSP_R2)
240 if (VP8GetCPUInfo(kMIPSdspR2)) {
241 VP8FiltersInitMIPSdspR2();
242 }
243 #endif
244 #if defined(WEBP_USE_MSA)
245 if (VP8GetCPUInfo(kMSA)) {
246 VP8FiltersInitMSA();
247 }
248 #endif
249 }
250
251 #if defined(WEBP_HAVE_NEON)
252 if (WEBP_NEON_OMIT_C_CODE ||
253 (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
254 VP8FiltersInitNEON();
255 }
256 #endif
257
258 assert(WebPUnfilters[WEBP_FILTER_NONE] != NULL);
259 assert(WebPUnfilters[WEBP_FILTER_HORIZONTAL] != NULL);
260 assert(WebPUnfilters[WEBP_FILTER_VERTICAL] != NULL);
261 assert(WebPUnfilters[WEBP_FILTER_GRADIENT] != NULL);
262 assert(WebPFilters[WEBP_FILTER_HORIZONTAL] != NULL);
263 assert(WebPFilters[WEBP_FILTER_VERTICAL] != NULL);
264 assert(WebPFilters[WEBP_FILTER_GRADIENT] != NULL);
265 }
266