1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "media/base/simd/convert_yuv_to_rgb.h" 6 #include "media/base/simd/yuv_to_rgb_table.h" 7 8 namespace media { 9 10 #define packuswb(x) ((x) < 0 ? 0 : ((x) > 255 ? 255 : (x))) 11 #define paddsw(x, y) (((x) + (y)) < -32768 ? -32768 : \ 12 (((x) + (y)) > 32767 ? 32767 : ((x) + (y)))) 13 14 // On Android, pixel layout is RGBA (see skia/include/core/SkColorPriv.h); 15 // however, other Chrome platforms use BGRA (see skia/config/SkUserConfig.h). 16 // Ideally, android should not use the functions here due to performance issue 17 // (http://crbug.com/249980). 18 #if defined(OS_ANDROID) 19 #define SK_R32_SHIFT 0 20 #define SK_G32_SHIFT 8 21 #define SK_B32_SHIFT 16 22 #define SK_A32_SHIFT 24 23 #else 24 #define SK_B32_SHIFT 0 25 #define SK_G32_SHIFT 8 26 #define SK_R32_SHIFT 16 27 #define SK_A32_SHIFT 24 28 #endif 29 30 static inline void ConvertYUVToRGB32_C(uint8 y, 31 uint8 u, 32 uint8 v, 33 uint8* rgb_buf) { 34 int b = kCoefficientsRgbY[256+u][0]; 35 int g = kCoefficientsRgbY[256+u][1]; 36 int r = kCoefficientsRgbY[256+u][2]; 37 int a = kCoefficientsRgbY[256+u][3]; 38 39 b = paddsw(b, kCoefficientsRgbY[512+v][0]); 40 g = paddsw(g, kCoefficientsRgbY[512+v][1]); 41 r = paddsw(r, kCoefficientsRgbY[512+v][2]); 42 a = paddsw(a, kCoefficientsRgbY[512+v][3]); 43 44 b = paddsw(b, kCoefficientsRgbY[y][0]); 45 g = paddsw(g, kCoefficientsRgbY[y][1]); 46 r = paddsw(r, kCoefficientsRgbY[y][2]); 47 a = paddsw(a, kCoefficientsRgbY[y][3]); 48 49 b >>= 6; 50 g >>= 6; 51 r >>= 6; 52 a >>= 6; 53 54 *reinterpret_cast<uint32*>(rgb_buf) = (packuswb(b) << SK_B32_SHIFT) | 55 (packuswb(g) << SK_G32_SHIFT) | 56 (packuswb(r) << SK_R32_SHIFT) | 57 (packuswb(a) << SK_A32_SHIFT); 58 } 59 60 static inline void ConvertYUVAToARGB_C(uint8 y, 61 uint8 u, 62 uint8 v, 63 uint8 a, 64 uint8* rgb_buf) { 65 int b = kCoefficientsRgbY[256+u][0]; 66 int g = kCoefficientsRgbY[256+u][1]; 67 int r = kCoefficientsRgbY[256+u][2]; 68 69 b = paddsw(b, kCoefficientsRgbY[512+v][0]); 70 g = paddsw(g, kCoefficientsRgbY[512+v][1]); 71 r = paddsw(r, kCoefficientsRgbY[512+v][2]); 72 73 b = paddsw(b, kCoefficientsRgbY[y][0]); 74 g = paddsw(g, kCoefficientsRgbY[y][1]); 75 r = paddsw(r, kCoefficientsRgbY[y][2]); 76 77 b >>= 6; 78 g >>= 6; 79 r >>= 6; 80 81 b = packuswb(b) * a >> 8; 82 g = packuswb(g) * a >> 8; 83 r = packuswb(r) * a >> 8; 84 85 *reinterpret_cast<uint32*>(rgb_buf) = (b << SK_B32_SHIFT) | 86 (g << SK_G32_SHIFT) | 87 (r << SK_R32_SHIFT) | 88 (a << SK_A32_SHIFT); 89 } 90 91 void ConvertYUVToRGB32Row_C(const uint8* y_buf, 92 const uint8* u_buf, 93 const uint8* v_buf, 94 uint8* rgb_buf, 95 ptrdiff_t width) { 96 for (int x = 0; x < width; x += 2) { 97 uint8 u = u_buf[x >> 1]; 98 uint8 v = v_buf[x >> 1]; 99 uint8 y0 = y_buf[x]; 100 ConvertYUVToRGB32_C(y0, u, v, rgb_buf); 101 if ((x + 1) < width) { 102 uint8 y1 = y_buf[x + 1]; 103 ConvertYUVToRGB32_C(y1, u, v, rgb_buf + 4); 104 } 105 rgb_buf += 8; // Advance 2 pixels. 106 } 107 } 108 109 void ConvertYUVAToARGBRow_C(const uint8* y_buf, 110 const uint8* u_buf, 111 const uint8* v_buf, 112 const uint8* a_buf, 113 uint8* rgba_buf, 114 ptrdiff_t width) { 115 for (int x = 0; x < width; x += 2) { 116 uint8 u = u_buf[x >> 1]; 117 uint8 v = v_buf[x >> 1]; 118 uint8 y0 = y_buf[x]; 119 uint8 a0 = a_buf[x]; 120 ConvertYUVAToARGB_C(y0, u, v, a0, rgba_buf); 121 if ((x + 1) < width) { 122 uint8 y1 = y_buf[x + 1]; 123 uint8 a1 = a_buf[x + 1]; 124 ConvertYUVAToARGB_C(y1, u, v, a1, rgba_buf + 4); 125 } 126 rgba_buf += 8; // Advance 2 pixels. 127 } 128 } 129 130 // 16.16 fixed point is used. A shift by 16 isolates the integer. 131 // A shift by 17 is used to further subsample the chrominence channels. 132 // & 0xffff isolates the fixed point fraction. >> 2 to get the upper 2 bits, 133 // for 1/65536 pixel accurate interpolation. 134 void ScaleYUVToRGB32Row_C(const uint8* y_buf, 135 const uint8* u_buf, 136 const uint8* v_buf, 137 uint8* rgb_buf, 138 ptrdiff_t width, 139 ptrdiff_t source_dx) { 140 int x = 0; 141 for (int i = 0; i < width; i += 2) { 142 int y = y_buf[x >> 16]; 143 int u = u_buf[(x >> 17)]; 144 int v = v_buf[(x >> 17)]; 145 ConvertYUVToRGB32_C(y, u, v, rgb_buf); 146 x += source_dx; 147 if ((i + 1) < width) { 148 y = y_buf[x >> 16]; 149 ConvertYUVToRGB32_C(y, u, v, rgb_buf+4); 150 x += source_dx; 151 } 152 rgb_buf += 8; 153 } 154 } 155 156 void LinearScaleYUVToRGB32Row_C(const uint8* y_buf, 157 const uint8* u_buf, 158 const uint8* v_buf, 159 uint8* rgb_buf, 160 ptrdiff_t width, 161 ptrdiff_t source_dx) { 162 // Avoid point-sampling for down-scaling by > 2:1. 163 int source_x = 0; 164 if (source_dx >= 0x20000) 165 source_x += 0x8000; 166 LinearScaleYUVToRGB32RowWithRange_C(y_buf, u_buf, v_buf, rgb_buf, width, 167 source_x, source_dx); 168 } 169 170 void LinearScaleYUVToRGB32RowWithRange_C(const uint8* y_buf, 171 const uint8* u_buf, 172 const uint8* v_buf, 173 uint8* rgb_buf, 174 int dest_width, 175 int x, 176 int source_dx) { 177 for (int i = 0; i < dest_width; i += 2) { 178 int y0 = y_buf[x >> 16]; 179 int y1 = y_buf[(x >> 16) + 1]; 180 int u0 = u_buf[(x >> 17)]; 181 int u1 = u_buf[(x >> 17) + 1]; 182 int v0 = v_buf[(x >> 17)]; 183 int v1 = v_buf[(x >> 17) + 1]; 184 int y_frac = (x & 65535); 185 int uv_frac = ((x >> 1) & 65535); 186 int y = (y_frac * y1 + (y_frac ^ 65535) * y0) >> 16; 187 int u = (uv_frac * u1 + (uv_frac ^ 65535) * u0) >> 16; 188 int v = (uv_frac * v1 + (uv_frac ^ 65535) * v0) >> 16; 189 ConvertYUVToRGB32_C(y, u, v, rgb_buf); 190 x += source_dx; 191 if ((i + 1) < dest_width) { 192 y0 = y_buf[x >> 16]; 193 y1 = y_buf[(x >> 16) + 1]; 194 y_frac = (x & 65535); 195 y = (y_frac * y1 + (y_frac ^ 65535) * y0) >> 16; 196 ConvertYUVToRGB32_C(y, u, v, rgb_buf+4); 197 x += source_dx; 198 } 199 rgb_buf += 8; 200 } 201 } 202 203 void ConvertYUVToRGB32_C(const uint8* yplane, 204 const uint8* uplane, 205 const uint8* vplane, 206 uint8* rgbframe, 207 int width, 208 int height, 209 int ystride, 210 int uvstride, 211 int rgbstride, 212 YUVType yuv_type) { 213 unsigned int y_shift = yuv_type; 214 for (int y = 0; y < height; ++y) { 215 uint8* rgb_row = rgbframe + y * rgbstride; 216 const uint8* y_ptr = yplane + y * ystride; 217 const uint8* u_ptr = uplane + (y >> y_shift) * uvstride; 218 const uint8* v_ptr = vplane + (y >> y_shift) * uvstride; 219 220 ConvertYUVToRGB32Row_C(y_ptr, 221 u_ptr, 222 v_ptr, 223 rgb_row, 224 width); 225 } 226 } 227 228 void ConvertYUVAToARGB_C(const uint8* yplane, 229 const uint8* uplane, 230 const uint8* vplane, 231 const uint8* aplane, 232 uint8* rgbaframe, 233 int width, 234 int height, 235 int ystride, 236 int uvstride, 237 int astride, 238 int rgbastride, 239 YUVType yuv_type) { 240 unsigned int y_shift = yuv_type; 241 for (int y = 0; y < height; y++) { 242 uint8* rgba_row = rgbaframe + y * rgbastride; 243 const uint8* y_ptr = yplane + y * ystride; 244 const uint8* u_ptr = uplane + (y >> y_shift) * uvstride; 245 const uint8* v_ptr = vplane + (y >> y_shift) * uvstride; 246 const uint8* a_ptr = aplane + y * astride; 247 248 ConvertYUVAToARGBRow_C(y_ptr, 249 u_ptr, 250 v_ptr, 251 a_ptr, 252 rgba_row, 253 width); 254 } 255 } 256 257 } // namespace media 258