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