1a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Copyright 2010 Google Inc. All Rights Reserved.
29aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//
30406ce1417f76f2034833414dcecc9f56253640cVikas Arora// Use of this source code is governed by a BSD-style license
40406ce1417f76f2034833414dcecc9f56253640cVikas Arora// that can be found in the COPYING file in the root of the source
50406ce1417f76f2034833414dcecc9f56253640cVikas Arora// tree. An additional intellectual property rights grant can be found
60406ce1417f76f2034833414dcecc9f56253640cVikas Arora// in the file PATENTS. All contributing project authors may
70406ce1417f76f2034833414dcecc9f56253640cVikas Arora// be found in the AUTHORS file in the root of the source tree.
89aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// -----------------------------------------------------------------------------
99aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//
10a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// inline YUV<->RGB conversion function
119aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//
121e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// The exact naming is Y'CbCr, following the ITU-R BT.601 standard.
131e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// More information at: http://en.wikipedia.org/wiki/YCbCr
141e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16
151e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128
161e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128
178b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// We use 16bit fixed point operations for RGB->YUV conversion (YUV_FIX).
181e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//
191e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// For the Y'CbCr to RGB conversion, the BT.601 specification reads:
201e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//   R = 1.164 * (Y-16) + 1.596 * (V-128)
211e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//   G = 1.164 * (Y-16) - 0.813 * (V-128) - 0.391 * (U-128)
221e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//   B = 1.164 * (Y-16)                   + 2.018 * (U-128)
231e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// where Y is in the [16,235] range, and U/V in the [16,240] range.
240406ce1417f76f2034833414dcecc9f56253640cVikas Arora// In the table-lookup version (WEBP_YUV_USE_TABLE), the common factor
250406ce1417f76f2034833414dcecc9f56253640cVikas Arora// "1.164 * (Y-16)" can be handled as an offset in the VP8kClip[] table.
268b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// So in this case the formulae should read:
271e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//   R = 1.164 * [Y + 1.371 * (V-128)                  ] - 18.624
281e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//   G = 1.164 * [Y - 0.698 * (V-128) - 0.336 * (U-128)] - 18.624
291e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//   B = 1.164 * [Y                   + 1.733 * (U-128)] - 18.624
308b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// once factorized.
318b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// For YUV->RGB conversion, only 14bit fixed precision is used (YUV_FIX2).
328b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// That's the maximum possible for a convenient ARM implementation.
331e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora//
349aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// Author: Skal (pascal.massimino@gmail.com)
359aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
36a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#ifndef WEBP_DSP_YUV_H_
37a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#define WEBP_DSP_YUV_H_
389aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
398b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#include "./dsp.h"
40a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include "../dec/decode_vp8.h"
419aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
420406ce1417f76f2034833414dcecc9f56253640cVikas Arora// Define the following to use the LUT-based code:
438b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// #define WEBP_YUV_USE_TABLE
440406ce1417f76f2034833414dcecc9f56253640cVikas Arora
451e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora#if defined(WEBP_EXPERIMENTAL_FEATURES)
461e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// Do NOT activate this feature for real compression. This is only experimental!
471e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// This flag is for comparison purpose against JPEG's "YUVj" natural colorspace.
481e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// This colorspace is close to Rec.601's Y'CbCr model with the notable
491e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// difference of allowing larger range for luma/chroma.
501e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// See http://en.wikipedia.org/wiki/YCbCr#JPEG_conversion paragraph, and its
511e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// difference with http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
521e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// #define USE_YUVj
531e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora#endif
5488fe2b83c4b9232cd08729556fd0485d6a6a92cdVikas Arora
55a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
56a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// YUV -> RGB conversion
57a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
588b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#ifdef __cplusplus
599aea642eefa7a641ab8b89d953251939221d2719Eric Hassoldextern "C" {
609aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#endif
619aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
628b720228d581a84fd173b6dcb2fa295b59db489aVikas Aroraenum {
638b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  YUV_FIX = 16,                    // fixed-point precision for RGB->YUV
648b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  YUV_HALF = 1 << (YUV_FIX - 1),
658b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  YUV_MASK = (256 << YUV_FIX) - 1,
668b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  YUV_RANGE_MIN = -227,            // min value of r/g/b output
678b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  YUV_RANGE_MAX = 256 + 226,       // max value of r/g/b output
688b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
698b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  YUV_FIX2 = 14,                   // fixed-point precision for YUV->RGB
708b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  YUV_HALF2 = 1 << (YUV_FIX2 - 1),
718b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  YUV_MASK2 = (256 << YUV_FIX2) - 1
729aea642eefa7a641ab8b89d953251939221d2719Eric Hassold};
730406ce1417f76f2034833414dcecc9f56253640cVikas Arora
748b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// These constants are 14b fixed-point version of ITU-R BT.601 constants.
758b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#define kYScale 19077    // 1.164 = 255 / 219
768b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#define kVToR   26149    // 1.596 = 255 / 112 * 0.701
778b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#define kUToG   6419     // 0.391 = 255 / 112 * 0.886 * 0.114 / 0.587
788b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#define kVToG   13320    // 0.813 = 255 / 112 * 0.701 * 0.299 / 0.587
798b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#define kUToB   33050    // 2.018 = 255 / 112 * 0.886
808b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#define kRCst (-kYScale * 16 - kVToR * 128 + YUV_HALF2)
818b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#define kGCst (-kYScale * 16 + kUToG * 128 + kVToG * 128 + YUV_HALF2)
828b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#define kBCst (-kYScale * 16 - kUToB * 128 + YUV_HALF2)
830406ce1417f76f2034833414dcecc9f56253640cVikas Arora
848b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora//------------------------------------------------------------------------------
858b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
868b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#if !defined(WEBP_YUV_USE_TABLE)
878b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
888b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// slower on x86 by ~7-8%, but bit-exact with the SSE2 version
898b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
908b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE int VP8Clip8(int v) {
918b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return ((v & ~YUV_MASK2) == 0) ? (v >> YUV_FIX2) : (v < 0) ? 0 : 255;
928b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
938b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
948b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE int VP8YUVToR(int y, int v) {
958b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return VP8Clip8(kYScale * y + kVToR * v + kRCst);
968b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
978b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
988b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE int VP8YUVToG(int y, int u, int v) {
998b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return VP8Clip8(kYScale * y - kUToG * u - kVToG * v + kGCst);
1008b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
1018b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
1028b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE int VP8YUVToB(int y, int u) {
1038b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return VP8Clip8(kYScale * y + kUToB * u + kBCst);
1048b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
1059aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
1068b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE void VP8YuvToRgb(int y, int u, int v,
107a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                    uint8_t* const rgb) {
1088b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  rgb[0] = VP8YUVToR(y, v);
1098b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  rgb[1] = VP8YUVToG(y, u, v);
1108b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  rgb[2] = VP8YUVToB(y, u);
1119aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
1129aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
1138b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE void VP8YuvToBgr(int y, int u, int v,
1140406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                    uint8_t* const bgr) {
1158b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  bgr[0] = VP8YUVToB(y, u);
1168b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  bgr[1] = VP8YUVToG(y, u, v);
1178b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  bgr[2] = VP8YUVToR(y, v);
1180406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
1190406ce1417f76f2034833414dcecc9f56253640cVikas Arora
1208b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE void VP8YuvToRgb565(int y, int u, int v,
121a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                       uint8_t* const rgb) {
1228b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int r = VP8YUVToR(y, v);      // 5 usable bits
1238b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int g = VP8YUVToG(y, u, v);   // 6 usable bits
1248b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int b = VP8YUVToB(y, u);      // 5 usable bits
1258b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int rg = (r & 0xf8) | (g >> 5);
1268b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int gb = ((g << 3) & 0xe0) | (b >> 3);
1271e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora#ifdef WEBP_SWAP_16BIT_CSP
1281e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  rgb[0] = gb;
1291e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  rgb[1] = rg;
13088fe2b83c4b9232cd08729556fd0485d6a6a92cdVikas Arora#else
1311e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  rgb[0] = rg;
1321e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  rgb[1] = gb;
13388fe2b83c4b9232cd08729556fd0485d6a6a92cdVikas Arora#endif
134466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
135466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
1368b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE void VP8YuvToRgba4444(int y, int u, int v,
137466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora                                         uint8_t* const argb) {
1388b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int r = VP8YUVToR(y, v);        // 4 usable bits
1398b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int g = VP8YUVToG(y, u, v);     // 4 usable bits
1408b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int b = VP8YUVToB(y, u);        // 4 usable bits
1418b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int rg = (r & 0xf0) | (g >> 4);
1428b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int ba = (b & 0xf0) | 0x0f;     // overwrite the lower 4 bits
1431e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora#ifdef WEBP_SWAP_16BIT_CSP
1441e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  argb[0] = ba;
1451e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  argb[1] = rg;
14688fe2b83c4b9232cd08729556fd0485d6a6a92cdVikas Arora#else
1471e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  argb[0] = rg;
1481e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  argb[1] = ba;
14988fe2b83c4b9232cd08729556fd0485d6a6a92cdVikas Arora#endif
1509aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
1519aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
1528b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#else
1530406ce1417f76f2034833414dcecc9f56253640cVikas Arora
1548b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// Table-based version, not totally equivalent to the SSE2 version.
1558b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// Rounding diff is only +/-1 though.
1560406ce1417f76f2034833414dcecc9f56253640cVikas Arora
1578b720228d581a84fd173b6dcb2fa295b59db489aVikas Aroraextern int16_t VP8kVToR[256], VP8kUToB[256];
1588b720228d581a84fd173b6dcb2fa295b59db489aVikas Aroraextern int32_t VP8kVToG[256], VP8kUToG[256];
1598b720228d581a84fd173b6dcb2fa295b59db489aVikas Aroraextern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
1608b720228d581a84fd173b6dcb2fa295b59db489aVikas Aroraextern uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
1610406ce1417f76f2034833414dcecc9f56253640cVikas Arora
1628b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE void VP8YuvToRgb(int y, int u, int v,
1630406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                    uint8_t* const rgb) {
1648b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int r_off = VP8kVToR[v];
1658b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
1668b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int b_off = VP8kUToB[u];
1678b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  rgb[0] = VP8kClip[y + r_off - YUV_RANGE_MIN];
1688b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  rgb[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
1698b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN];
1700406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
1710406ce1417f76f2034833414dcecc9f56253640cVikas Arora
1728b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE void VP8YuvToBgr(int y, int u, int v,
173a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                    uint8_t* const bgr) {
1748b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int r_off = VP8kVToR[v];
1758b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
1768b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int b_off = VP8kUToB[u];
1778b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  bgr[0] = VP8kClip[y + b_off - YUV_RANGE_MIN];
1788b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  bgr[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
1798b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  bgr[2] = VP8kClip[y + r_off - YUV_RANGE_MIN];
1800406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
1810406ce1417f76f2034833414dcecc9f56253640cVikas Arora
1828b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE void VP8YuvToRgb565(int y, int u, int v,
1830406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                       uint8_t* const rgb) {
1848b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int r_off = VP8kVToR[v];
1858b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
1868b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int b_off = VP8kUToB[u];
1878b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int rg = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) |
1888b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora                  (VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5));
1898b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int gb = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) |
1908b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora                   (VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3));
1910406ce1417f76f2034833414dcecc9f56253640cVikas Arora#ifdef WEBP_SWAP_16BIT_CSP
1920406ce1417f76f2034833414dcecc9f56253640cVikas Arora  rgb[0] = gb;
1930406ce1417f76f2034833414dcecc9f56253640cVikas Arora  rgb[1] = rg;
1940406ce1417f76f2034833414dcecc9f56253640cVikas Arora#else
1950406ce1417f76f2034833414dcecc9f56253640cVikas Arora  rgb[0] = rg;
1960406ce1417f76f2034833414dcecc9f56253640cVikas Arora  rgb[1] = gb;
1970406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif
1980406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
1990406ce1417f76f2034833414dcecc9f56253640cVikas Arora
2008b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE void VP8YuvToRgba4444(int y, int u, int v,
2010406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                         uint8_t* const argb) {
2028b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int r_off = VP8kVToR[v];
2038b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
2048b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int b_off = VP8kUToB[u];
2058b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int rg = ((VP8kClip4Bits[y + r_off - YUV_RANGE_MIN] << 4) |
2068b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora                   VP8kClip4Bits[y + g_off - YUV_RANGE_MIN]);
2078b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const int ba = (VP8kClip4Bits[y + b_off - YUV_RANGE_MIN] << 4) | 0x0f;
2080406ce1417f76f2034833414dcecc9f56253640cVikas Arora#ifdef WEBP_SWAP_16BIT_CSP
2090406ce1417f76f2034833414dcecc9f56253640cVikas Arora  argb[0] = ba;
2100406ce1417f76f2034833414dcecc9f56253640cVikas Arora  argb[1] = rg;
2110406ce1417f76f2034833414dcecc9f56253640cVikas Arora#else
2120406ce1417f76f2034833414dcecc9f56253640cVikas Arora  argb[0] = rg;
2130406ce1417f76f2034833414dcecc9f56253640cVikas Arora  argb[1] = ba;
2140406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif
2150406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
2160406ce1417f76f2034833414dcecc9f56253640cVikas Arora
2170406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif  // WEBP_YUV_USE_TABLE
2180406ce1417f76f2034833414dcecc9f56253640cVikas Arora
2198b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora//-----------------------------------------------------------------------------
2208b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// Alpha handling variants
2218b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
2220406ce1417f76f2034833414dcecc9f56253640cVikas Arorastatic WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
2230406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                     uint8_t* const argb) {
2240406ce1417f76f2034833414dcecc9f56253640cVikas Arora  argb[0] = 0xff;
2250406ce1417f76f2034833414dcecc9f56253640cVikas Arora  VP8YuvToRgb(y, u, v, argb + 1);
2269aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
2279aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
228a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic WEBP_INLINE void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v,
229a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                     uint8_t* const bgra) {
2309aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  VP8YuvToBgr(y, u, v, bgra);
2319aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  bgra[3] = 0xff;
2329aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
2339aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
234a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arorastatic WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
235a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora                                     uint8_t* const rgba) {
236466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  VP8YuvToRgb(y, u, v, rgba);
237466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora  rgba[3] = 0xff;
238466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora}
239466727975bcc57c0c5597bcd0747a2fe4777b303Vikas Arora
2409aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// Must be called before everything, to initialize the tables.
24103d5e34c70f174c16282b0efdc6bb9473df5f8f1Vikas Aroravoid VP8YUVInit(void);
2429aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
2438b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora//-----------------------------------------------------------------------------
2448b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// SSE2 extra functions (mostly for upsampling_sse2.c)
2458b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
2468b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#if defined(WEBP_USE_SSE2)
2478b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
248af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// When the following is defined, tables are initialized statically, adding ~12k
249af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// to the binary size. Otherwise, they are initialized at run-time (small cost).
250af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#define WEBP_YUV_USE_SSE2_TABLES
251af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora
2528b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#if defined(FANCY_UPSAMPLING)
2538b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// Process 32 pixels and store the result (24b or 32b per pixel) in *dst.
2548b720228d581a84fd173b6dcb2fa295b59db489aVikas Aroravoid VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
2558b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora                    uint8_t* dst);
2568b720228d581a84fd173b6dcb2fa295b59db489aVikas Aroravoid VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
2578b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora                   uint8_t* dst);
2588b720228d581a84fd173b6dcb2fa295b59db489aVikas Aroravoid VP8YuvToBgra32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
2598b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora                    uint8_t* dst);
2608b720228d581a84fd173b6dcb2fa295b59db489aVikas Aroravoid VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
2618b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora                   uint8_t* dst);
2628b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#endif  // FANCY_UPSAMPLING
2638b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
2648b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// Must be called to initialize tables before using the functions.
2658b720228d581a84fd173b6dcb2fa295b59db489aVikas Aroravoid VP8YUVInitSSE2(void);
2668b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
2678b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#endif    // WEBP_USE_SSE2
2688b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
269a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------
270a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// RGB -> YUV conversion
271a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
2728b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// Stub functions that can be called with various rounding values:
2738b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE int VP8ClipUV(int uv, int rounding) {
2748b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  uv = (uv + rounding + (128 << (YUV_FIX + 2))) >> (YUV_FIX + 2);
2758b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return ((uv & ~0xff) == 0) ? uv : (uv < 0) ? 0 : 255;
276a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
277a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
2781e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora#ifndef USE_YUVj
2791e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
2808b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
281a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora  const int luma = 16839 * r + 33059 * g + 6420 * b;
2828b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return (luma + rounding + (16 << YUV_FIX)) >> YUV_FIX;  // no need to clip
283a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
284a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
2858b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE int VP8RGBToU(int r, int g, int b, int rounding) {
2861e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  const int u = -9719 * r - 19081 * g + 28800 * b;
2878b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return VP8ClipUV(u, rounding);
2881e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora}
2891e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
2908b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
2911e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  const int v = +28800 * r - 24116 * g - 4684 * b;
2928b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return VP8ClipUV(v, rounding);
2931e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora}
2941e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
2951e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora#else
2961e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
2971e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// This JPEG-YUV colorspace, only for comparison!
2988b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// These are also 16bit precision coefficients from Rec.601, but with full
2991e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// [0..255] output range.
3008b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
3011e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  const int luma = 19595 * r + 38470 * g + 7471 * b;
3028b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return (luma + rounding) >> YUV_FIX;  // no need to clip
3031e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora}
3041e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
305af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic WEBP_INLINE int VP8RGBToU(int r, int g, int b, int rounding) {
3061e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  const int u = -11058 * r - 21710 * g + 32768 * b;
3078b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return VP8ClipUV(u, rounding);
308a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
309a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
310af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
3111e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora  const int v = 32768 * r - 27439 * g - 5329 * b;
3128b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return VP8ClipUV(v, rounding);
313a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora}
314a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora
3151e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora#endif    // USE_YUVj
3161e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora
3178b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#ifdef __cplusplus
3189aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}    // extern "C"
3199aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#endif
3209aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
321a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#endif  /* WEBP_DSP_YUV_H_ */
322