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