go-libwebp

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

yuv.c (9728B)


      1 // Copyright 2010 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 // YUV->RGB conversion functions
     11 //
     12 // Author: Skal (pascal.massimino@gmail.com)
     13 
     14 #include <assert.h>
     15 #include <stdlib.h>
     16 
     17 #include "src/dsp/cpu.h"
     18 #include "src/webp/types.h"
     19 #include "src/dsp/dsp.h"
     20 #include "src/dsp/yuv.h"
     21 #include "src/webp/decode.h"
     22 
     23 //-----------------------------------------------------------------------------
     24 // Plain-C version
     25 
     26 #define ROW_FUNC(FUNC_NAME, FUNC, XSTEP)                                       \
     27 static void FUNC_NAME(const uint8_t* WEBP_RESTRICT y,                          \
     28                       const uint8_t* WEBP_RESTRICT u,                          \
     29                       const uint8_t* WEBP_RESTRICT v,                          \
     30                       uint8_t* WEBP_RESTRICT dst, int len) {                   \
     31   const uint8_t* const end = dst + (len & ~1) * (XSTEP);                       \
     32   while (dst != end) {                                                         \
     33     FUNC(y[0], u[0], v[0], dst);                                               \
     34     FUNC(y[1], u[0], v[0], dst + (XSTEP));                                     \
     35     y += 2;                                                                    \
     36     ++u;                                                                       \
     37     ++v;                                                                       \
     38     dst += 2 * (XSTEP);                                                        \
     39   }                                                                            \
     40   if (len & 1) {                                                               \
     41     FUNC(y[0], u[0], v[0], dst);                                               \
     42   }                                                                            \
     43 }                                                                              \
     44 
     45 // All variants implemented.
     46 ROW_FUNC(YuvToRgbRow,      VP8YuvToRgb,  3)
     47 ROW_FUNC(YuvToBgrRow,      VP8YuvToBgr,  3)
     48 ROW_FUNC(YuvToRgbaRow,     VP8YuvToRgba, 4)
     49 ROW_FUNC(YuvToBgraRow,     VP8YuvToBgra, 4)
     50 ROW_FUNC(YuvToArgbRow,     VP8YuvToArgb, 4)
     51 ROW_FUNC(YuvToRgba4444Row, VP8YuvToRgba4444, 2)
     52 ROW_FUNC(YuvToRgb565Row,   VP8YuvToRgb565, 2)
     53 
     54 #undef ROW_FUNC
     55 
     56 // Main call for processing a plane with a WebPSamplerRowFunc function:
     57 void WebPSamplerProcessPlane(const uint8_t* WEBP_RESTRICT y, int y_stride,
     58                              const uint8_t* WEBP_RESTRICT u,
     59                              const uint8_t* WEBP_RESTRICT v, int uv_stride,
     60                              uint8_t* WEBP_RESTRICT dst, int dst_stride,
     61                              int width, int height, WebPSamplerRowFunc func) {
     62   int j;
     63   for (j = 0; j < height; ++j) {
     64     func(y, u, v, dst, width);
     65     y += y_stride;
     66     if (j & 1) {
     67       u += uv_stride;
     68       v += uv_stride;
     69     }
     70     dst += dst_stride;
     71   }
     72 }
     73 
     74 //-----------------------------------------------------------------------------
     75 // Main call
     76 
     77 WebPSamplerRowFunc WebPSamplers[MODE_LAST];
     78 
     79 extern VP8CPUInfo VP8GetCPUInfo;
     80 extern void WebPInitSamplersSSE2(void);
     81 extern void WebPInitSamplersSSE41(void);
     82 extern void WebPInitSamplersMIPS32(void);
     83 extern void WebPInitSamplersMIPSdspR2(void);
     84 
     85 WEBP_DSP_INIT_FUNC(WebPInitSamplers) {
     86   WebPSamplers[MODE_RGB]       = YuvToRgbRow;
     87   WebPSamplers[MODE_RGBA]      = YuvToRgbaRow;
     88   WebPSamplers[MODE_BGR]       = YuvToBgrRow;
     89   WebPSamplers[MODE_BGRA]      = YuvToBgraRow;
     90   WebPSamplers[MODE_ARGB]      = YuvToArgbRow;
     91   WebPSamplers[MODE_RGBA_4444] = YuvToRgba4444Row;
     92   WebPSamplers[MODE_RGB_565]   = YuvToRgb565Row;
     93   WebPSamplers[MODE_rgbA]      = YuvToRgbaRow;
     94   WebPSamplers[MODE_bgrA]      = YuvToBgraRow;
     95   WebPSamplers[MODE_Argb]      = YuvToArgbRow;
     96   WebPSamplers[MODE_rgbA_4444] = YuvToRgba4444Row;
     97 
     98   // If defined, use CPUInfo() to overwrite some pointers with faster versions.
     99   if (VP8GetCPUInfo != NULL) {
    100 #if defined(WEBP_HAVE_SSE2)
    101     if (VP8GetCPUInfo(kSSE2)) {
    102       WebPInitSamplersSSE2();
    103     }
    104 #endif  // WEBP_HAVE_SSE2
    105 #if defined(WEBP_HAVE_SSE41)
    106     if (VP8GetCPUInfo(kSSE4_1)) {
    107       WebPInitSamplersSSE41();
    108     }
    109 #endif  // WEBP_HAVE_SSE41
    110 #if defined(WEBP_USE_MIPS32)
    111     if (VP8GetCPUInfo(kMIPS32)) {
    112       WebPInitSamplersMIPS32();
    113     }
    114 #endif  // WEBP_USE_MIPS32
    115 #if defined(WEBP_USE_MIPS_DSP_R2)
    116     if (VP8GetCPUInfo(kMIPSdspR2)) {
    117       WebPInitSamplersMIPSdspR2();
    118     }
    119 #endif  // WEBP_USE_MIPS_DSP_R2
    120   }
    121 }
    122 
    123 //-----------------------------------------------------------------------------
    124 // ARGB -> YUV converters
    125 
    126 static void ConvertARGBToY_C(const uint32_t* WEBP_RESTRICT argb,
    127                              uint8_t* WEBP_RESTRICT y, int width) {
    128   int i;
    129   for (i = 0; i < width; ++i) {
    130     const uint32_t p = argb[i];
    131     y[i] = VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >>  0) & 0xff,
    132                      YUV_HALF);
    133   }
    134 }
    135 
    136 void WebPConvertARGBToUV_C(const uint32_t* WEBP_RESTRICT argb,
    137                            uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v,
    138                            int src_width, int do_store) {
    139   // No rounding. Last pixel is dealt with separately.
    140   const int uv_width = src_width >> 1;
    141   int i;
    142   for (i = 0; i < uv_width; ++i) {
    143     const uint32_t v0 = argb[2 * i + 0];
    144     const uint32_t v1 = argb[2 * i + 1];
    145     // VP8RGBToU/V expects four accumulated pixels. Hence we need to
    146     // scale r/g/b value by a factor 2. We just shift v0/v1 one bit less.
    147     const int r = ((v0 >> 15) & 0x1fe) + ((v1 >> 15) & 0x1fe);
    148     const int g = ((v0 >>  7) & 0x1fe) + ((v1 >>  7) & 0x1fe);
    149     const int b = ((v0 <<  1) & 0x1fe) + ((v1 <<  1) & 0x1fe);
    150     const int tmp_u = VP8RGBToU(r, g, b, YUV_HALF << 2);
    151     const int tmp_v = VP8RGBToV(r, g, b, YUV_HALF << 2);
    152     if (do_store) {
    153       u[i] = tmp_u;
    154       v[i] = tmp_v;
    155     } else {
    156       // Approximated average-of-four. But it's an acceptable diff.
    157       u[i] = (u[i] + tmp_u + 1) >> 1;
    158       v[i] = (v[i] + tmp_v + 1) >> 1;
    159     }
    160   }
    161   if (src_width & 1) {       // last pixel
    162     const uint32_t v0 = argb[2 * i + 0];
    163     const int r = (v0 >> 14) & 0x3fc;
    164     const int g = (v0 >>  6) & 0x3fc;
    165     const int b = (v0 <<  2) & 0x3fc;
    166     const int tmp_u = VP8RGBToU(r, g, b, YUV_HALF << 2);
    167     const int tmp_v = VP8RGBToV(r, g, b, YUV_HALF << 2);
    168     if (do_store) {
    169       u[i] = tmp_u;
    170       v[i] = tmp_v;
    171     } else {
    172       u[i] = (u[i] + tmp_u + 1) >> 1;
    173       v[i] = (v[i] + tmp_v + 1) >> 1;
    174     }
    175   }
    176 }
    177 
    178 //-----------------------------------------------------------------------------
    179 
    180 static void ConvertRGB24ToY_C(const uint8_t* WEBP_RESTRICT rgb,
    181                               uint8_t* WEBP_RESTRICT y, int width) {
    182   int i;
    183   for (i = 0; i < width; ++i, rgb += 3) {
    184     y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF);
    185   }
    186 }
    187 
    188 static void ConvertBGR24ToY_C(const uint8_t* WEBP_RESTRICT bgr,
    189                               uint8_t* WEBP_RESTRICT y, int width) {
    190   int i;
    191   for (i = 0; i < width; ++i, bgr += 3) {
    192     y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF);
    193   }
    194 }
    195 
    196 void WebPConvertRGBA32ToUV_C(const uint16_t* WEBP_RESTRICT rgb,
    197                              uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v,
    198                              int width) {
    199   int i;
    200   for (i = 0; i < width; i += 1, rgb += 4) {
    201     const int r = rgb[0], g = rgb[1], b = rgb[2];
    202     u[i] = VP8RGBToU(r, g, b, YUV_HALF << 2);
    203     v[i] = VP8RGBToV(r, g, b, YUV_HALF << 2);
    204   }
    205 }
    206 
    207 //-----------------------------------------------------------------------------
    208 
    209 void (*WebPConvertRGB24ToY)(const uint8_t* WEBP_RESTRICT rgb,
    210                             uint8_t* WEBP_RESTRICT y, int width);
    211 void (*WebPConvertBGR24ToY)(const uint8_t* WEBP_RESTRICT bgr,
    212                             uint8_t* WEBP_RESTRICT y, int width);
    213 void (*WebPConvertRGBA32ToUV)(const uint16_t* WEBP_RESTRICT rgb,
    214                               uint8_t* WEBP_RESTRICT u,
    215                               uint8_t* WEBP_RESTRICT v, int width);
    216 
    217 void (*WebPConvertARGBToY)(const uint32_t* WEBP_RESTRICT argb,
    218                            uint8_t* WEBP_RESTRICT y, int width);
    219 void (*WebPConvertARGBToUV)(const uint32_t* WEBP_RESTRICT argb,
    220                             uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v,
    221                             int src_width, int do_store);
    222 
    223 extern void WebPInitConvertARGBToYUVSSE2(void);
    224 extern void WebPInitConvertARGBToYUVSSE41(void);
    225 extern void WebPInitConvertARGBToYUVNEON(void);
    226 
    227 WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
    228   WebPConvertARGBToY = ConvertARGBToY_C;
    229   WebPConvertARGBToUV = WebPConvertARGBToUV_C;
    230 
    231   WebPConvertRGB24ToY = ConvertRGB24ToY_C;
    232   WebPConvertBGR24ToY = ConvertBGR24ToY_C;
    233 
    234   WebPConvertRGBA32ToUV = WebPConvertRGBA32ToUV_C;
    235 
    236   if (VP8GetCPUInfo != NULL) {
    237 #if defined(WEBP_HAVE_SSE2)
    238     if (VP8GetCPUInfo(kSSE2)) {
    239       WebPInitConvertARGBToYUVSSE2();
    240     }
    241 #endif  // WEBP_HAVE_SSE2
    242 #if defined(WEBP_HAVE_SSE41)
    243     if (VP8GetCPUInfo(kSSE4_1)) {
    244       WebPInitConvertARGBToYUVSSE41();
    245     }
    246 #endif  // WEBP_HAVE_SSE41
    247   }
    248 
    249 #if defined(WEBP_HAVE_NEON)
    250   if (WEBP_NEON_OMIT_C_CODE ||
    251       (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
    252     WebPInitConvertARGBToYUVNEON();
    253   }
    254 #endif  // WEBP_HAVE_NEON
    255 
    256   assert(WebPConvertARGBToY != NULL);
    257   assert(WebPConvertARGBToUV != NULL);
    258   assert(WebPConvertRGB24ToY != NULL);
    259   assert(WebPConvertBGR24ToY != NULL);
    260   assert(WebPConvertRGBA32ToUV != NULL);
    261 }