tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
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 }