go-libwebp

Experimental translation from libwebp to Go source.
Log | Files | Refs | README | LICENSE

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 }