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