Home | History | Annotate | Download | only in dsp
      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