• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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