Home | History | Annotate | Download | only in dsp
      1 // Copyright 2014 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 // Rescaling functions
     11 //
     12 // Author: Skal (pascal.massimino (at) gmail.com)
     13 
     14 #include <assert.h>
     15 
     16 #include "src/dsp/dsp.h"
     17 #include "src/utils/rescaler_utils.h"
     18 
     19 //------------------------------------------------------------------------------
     20 // Implementations of critical functions ImportRow / ExportRow
     21 
     22 #define ROUNDER (WEBP_RESCALER_ONE >> 1)
     23 #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
     24 #define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
     25 
     26 //------------------------------------------------------------------------------
     27 // Row import
     28 
     29 void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk,
     30                                    const uint8_t* src) {
     31   const int x_stride = wrk->num_channels;
     32   const int x_out_max = wrk->dst_width * wrk->num_channels;
     33   int channel;
     34   assert(!WebPRescalerInputDone(wrk));
     35   assert(wrk->x_expand);
     36   for (channel = 0; channel < x_stride; ++channel) {
     37     int x_in = channel;
     38     int x_out = channel;
     39     // simple bilinear interpolation
     40     int accum = wrk->x_add;
     41     int left = src[x_in];
     42     int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left;
     43     x_in += x_stride;
     44     while (1) {
     45       wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
     46       x_out += x_stride;
     47       if (x_out >= x_out_max) break;
     48       accum -= wrk->x_sub;
     49       if (accum < 0) {
     50         left = right;
     51         x_in += x_stride;
     52         assert(x_in < wrk->src_width * x_stride);
     53         right = src[x_in];
     54         accum += wrk->x_add;
     55       }
     56     }
     57     assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0);
     58   }
     59 }
     60 
     61 void WebPRescalerImportRowShrink_C(WebPRescaler* const wrk,
     62                                    const uint8_t* src) {
     63   const int x_stride = wrk->num_channels;
     64   const int x_out_max = wrk->dst_width * wrk->num_channels;
     65   int channel;
     66   assert(!WebPRescalerInputDone(wrk));
     67   assert(!wrk->x_expand);
     68   for (channel = 0; channel < x_stride; ++channel) {
     69     int x_in = channel;
     70     int x_out = channel;
     71     uint32_t sum = 0;
     72     int accum = 0;
     73     while (x_out < x_out_max) {
     74       uint32_t base = 0;
     75       accum += wrk->x_add;
     76       while (accum > 0) {
     77         accum -= wrk->x_sub;
     78         assert(x_in < wrk->src_width * x_stride);
     79         base = src[x_in];
     80         sum += base;
     81         x_in += x_stride;
     82       }
     83       {        // Emit next horizontal pixel.
     84         const rescaler_t frac = base * (-accum);
     85         wrk->frow[x_out] = sum * wrk->x_sub - frac;
     86         // fresh fractional start for next pixel
     87         sum = (int)MULT_FIX(frac, wrk->fx_scale);
     88       }
     89       x_out += x_stride;
     90     }
     91     assert(accum == 0);
     92   }
     93 }
     94 
     95 //------------------------------------------------------------------------------
     96 // Row export
     97 
     98 void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) {
     99   int x_out;
    100   uint8_t* const dst = wrk->dst;
    101   rescaler_t* const irow = wrk->irow;
    102   const int x_out_max = wrk->dst_width * wrk->num_channels;
    103   const rescaler_t* const frow = wrk->frow;
    104   assert(!WebPRescalerOutputDone(wrk));
    105   assert(wrk->y_accum <= 0);
    106   assert(wrk->y_expand);
    107   assert(wrk->y_sub != 0);
    108   if (wrk->y_accum == 0) {
    109     for (x_out = 0; x_out < x_out_max; ++x_out) {
    110       const uint32_t J = frow[x_out];
    111       const int v = (int)MULT_FIX(J, wrk->fy_scale);
    112       dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
    113     }
    114   } else {
    115     const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
    116     const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
    117     for (x_out = 0; x_out < x_out_max; ++x_out) {
    118       const uint64_t I = (uint64_t)A * frow[x_out]
    119                        + (uint64_t)B * irow[x_out];
    120       const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
    121       const int v = (int)MULT_FIX(J, wrk->fy_scale);
    122       dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
    123     }
    124   }
    125 }
    126 
    127 void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
    128   int x_out;
    129   uint8_t* const dst = wrk->dst;
    130   rescaler_t* const irow = wrk->irow;
    131   const int x_out_max = wrk->dst_width * wrk->num_channels;
    132   const rescaler_t* const frow = wrk->frow;
    133   const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum);
    134   assert(!WebPRescalerOutputDone(wrk));
    135   assert(wrk->y_accum <= 0);
    136   assert(!wrk->y_expand);
    137   if (yscale) {
    138     for (x_out = 0; x_out < x_out_max; ++x_out) {
    139       const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale);
    140       const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
    141       dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
    142       irow[x_out] = frac;   // new fractional start
    143     }
    144   } else {
    145     for (x_out = 0; x_out < x_out_max; ++x_out) {
    146       const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
    147       dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
    148       irow[x_out] = 0;
    149     }
    150   }
    151 }
    152 
    153 #undef MULT_FIX_FLOOR
    154 #undef MULT_FIX
    155 #undef ROUNDER
    156 
    157 //------------------------------------------------------------------------------
    158 // Main entry calls
    159 
    160 void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) {
    161   assert(!WebPRescalerInputDone(wrk));
    162   if (!wrk->x_expand) {
    163     WebPRescalerImportRowShrink(wrk, src);
    164   } else {
    165     WebPRescalerImportRowExpand(wrk, src);
    166   }
    167 }
    168 
    169 void WebPRescalerExportRow(WebPRescaler* const wrk) {
    170   if (wrk->y_accum <= 0) {
    171     assert(!WebPRescalerOutputDone(wrk));
    172     if (wrk->y_expand) {
    173       WebPRescalerExportRowExpand(wrk);
    174     } else if (wrk->fxy_scale) {
    175       WebPRescalerExportRowShrink(wrk);
    176     } else {  // special case
    177       int i;
    178       assert(wrk->src_height == wrk->dst_height && wrk->x_add == 1);
    179       assert(wrk->src_width == 1 && wrk->dst_width <= 2);
    180       for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) {
    181         wrk->dst[i] = wrk->irow[i];
    182         wrk->irow[i] = 0;
    183       }
    184     }
    185     wrk->y_accum += wrk->y_add;
    186     wrk->dst += wrk->dst_stride;
    187     ++wrk->dst_y;
    188   }
    189 }
    190 
    191 //------------------------------------------------------------------------------
    192 
    193 WebPRescalerImportRowFunc WebPRescalerImportRowExpand;
    194 WebPRescalerImportRowFunc WebPRescalerImportRowShrink;
    195 
    196 WebPRescalerExportRowFunc WebPRescalerExportRowExpand;
    197 WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
    198 
    199 extern void WebPRescalerDspInitSSE2(void);
    200 extern void WebPRescalerDspInitMIPS32(void);
    201 extern void WebPRescalerDspInitMIPSdspR2(void);
    202 extern void WebPRescalerDspInitMSA(void);
    203 extern void WebPRescalerDspInitNEON(void);
    204 
    205 WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) {
    206 #if !defined(WEBP_REDUCE_SIZE)
    207 #if !WEBP_NEON_OMIT_C_CODE
    208   WebPRescalerExportRowExpand = WebPRescalerExportRowExpand_C;
    209   WebPRescalerExportRowShrink = WebPRescalerExportRowShrink_C;
    210 #endif
    211 
    212   WebPRescalerImportRowExpand = WebPRescalerImportRowExpand_C;
    213   WebPRescalerImportRowShrink = WebPRescalerImportRowShrink_C;
    214 
    215   if (VP8GetCPUInfo != NULL) {
    216 #if defined(WEBP_USE_SSE2)
    217     if (VP8GetCPUInfo(kSSE2)) {
    218       WebPRescalerDspInitSSE2();
    219     }
    220 #endif
    221 #if defined(WEBP_USE_MIPS32)
    222     if (VP8GetCPUInfo(kMIPS32)) {
    223       WebPRescalerDspInitMIPS32();
    224     }
    225 #endif
    226 #if defined(WEBP_USE_MIPS_DSP_R2)
    227     if (VP8GetCPUInfo(kMIPSdspR2)) {
    228       WebPRescalerDspInitMIPSdspR2();
    229     }
    230 #endif
    231 #if defined(WEBP_USE_MSA)
    232     if (VP8GetCPUInfo(kMSA)) {
    233       WebPRescalerDspInitMSA();
    234     }
    235 #endif
    236   }
    237 
    238 #if defined(WEBP_USE_NEON)
    239   if (WEBP_NEON_OMIT_C_CODE ||
    240       (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
    241     WebPRescalerDspInitNEON();
    242   }
    243 #endif
    244 
    245   assert(WebPRescalerExportRowExpand != NULL);
    246   assert(WebPRescalerExportRowShrink != NULL);
    247   assert(WebPRescalerImportRowExpand != NULL);
    248   assert(WebPRescalerImportRowShrink != NULL);
    249 #endif   // WEBP_REDUCE_SIZE
    250 }
    251