1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <media/stagefright/ColorConverter.h> 18 #include <media/stagefright/MediaDebug.h> 19 20 namespace android { 21 22 static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00; 23 24 ColorConverter::ColorConverter( 25 OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to) 26 : mSrcFormat(from), 27 mDstFormat(to), 28 mClip(NULL) { 29 } 30 31 ColorConverter::~ColorConverter() { 32 delete[] mClip; 33 mClip = NULL; 34 } 35 36 bool ColorConverter::isValid() const { 37 if (mDstFormat != OMX_COLOR_Format16bitRGB565) { 38 return false; 39 } 40 41 switch (mSrcFormat) { 42 case OMX_COLOR_FormatYUV420Planar: 43 case OMX_COLOR_FormatCbYCrY: 44 case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: 45 case OMX_COLOR_FormatYUV420SemiPlanar: 46 return true; 47 48 default: 49 return false; 50 } 51 } 52 53 void ColorConverter::convert( 54 size_t width, size_t height, 55 const void *srcBits, size_t srcSkip, 56 void *dstBits, size_t dstSkip) { 57 CHECK_EQ(mDstFormat, OMX_COLOR_Format16bitRGB565); 58 59 switch (mSrcFormat) { 60 case OMX_COLOR_FormatYUV420Planar: 61 convertYUV420Planar( 62 width, height, srcBits, srcSkip, dstBits, dstSkip); 63 break; 64 65 case OMX_COLOR_FormatCbYCrY: 66 convertCbYCrY( 67 width, height, srcBits, srcSkip, dstBits, dstSkip); 68 break; 69 70 case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: 71 convertQCOMYUV420SemiPlanar( 72 width, height, srcBits, srcSkip, dstBits, dstSkip); 73 break; 74 75 case OMX_COLOR_FormatYUV420SemiPlanar: 76 convertYUV420SemiPlanar( 77 width, height, srcBits, srcSkip, dstBits, dstSkip); 78 break; 79 80 default: 81 { 82 CHECK(!"Should not be here. Unknown color conversion."); 83 break; 84 } 85 } 86 } 87 88 void ColorConverter::convertCbYCrY( 89 size_t width, size_t height, 90 const void *srcBits, size_t srcSkip, 91 void *dstBits, size_t dstSkip) { 92 CHECK_EQ(srcSkip, 0); // Doesn't really make sense for YUV formats. 93 CHECK(dstSkip >= width * 2); 94 CHECK((dstSkip & 3) == 0); 95 96 uint8_t *kAdjustedClip = initClip(); 97 98 uint32_t *dst_ptr = (uint32_t *)dstBits; 99 100 const uint8_t *src = (const uint8_t *)srcBits; 101 102 for (size_t y = 0; y < height; ++y) { 103 for (size_t x = 0; x < width; x += 2) { 104 signed y1 = (signed)src[2 * x + 1] - 16; 105 signed y2 = (signed)src[2 * x + 3] - 16; 106 signed u = (signed)src[2 * x] - 128; 107 signed v = (signed)src[2 * x + 2] - 128; 108 109 signed u_b = u * 517; 110 signed u_g = -u * 100; 111 signed v_g = -v * 208; 112 signed v_r = v * 409; 113 114 signed tmp1 = y1 * 298; 115 signed b1 = (tmp1 + u_b) / 256; 116 signed g1 = (tmp1 + v_g + u_g) / 256; 117 signed r1 = (tmp1 + v_r) / 256; 118 119 signed tmp2 = y2 * 298; 120 signed b2 = (tmp2 + u_b) / 256; 121 signed g2 = (tmp2 + v_g + u_g) / 256; 122 signed r2 = (tmp2 + v_r) / 256; 123 124 uint32_t rgb1 = 125 ((kAdjustedClip[r1] >> 3) << 11) 126 | ((kAdjustedClip[g1] >> 2) << 5) 127 | (kAdjustedClip[b1] >> 3); 128 129 uint32_t rgb2 = 130 ((kAdjustedClip[r2] >> 3) << 11) 131 | ((kAdjustedClip[g2] >> 2) << 5) 132 | (kAdjustedClip[b2] >> 3); 133 134 dst_ptr[x / 2] = (rgb2 << 16) | rgb1; 135 } 136 137 src += width * 2; 138 dst_ptr += dstSkip / 4; 139 } 140 } 141 142 void ColorConverter::convertYUV420Planar( 143 size_t width, size_t height, 144 const void *srcBits, size_t srcSkip, 145 void *dstBits, size_t dstSkip) { 146 CHECK_EQ(srcSkip, 0); // Doesn't really make sense for YUV formats. 147 CHECK(dstSkip >= width * 2); 148 CHECK((dstSkip & 3) == 0); 149 150 uint8_t *kAdjustedClip = initClip(); 151 152 uint32_t *dst_ptr = (uint32_t *)dstBits; 153 const uint8_t *src_y = (const uint8_t *)srcBits; 154 155 const uint8_t *src_u = 156 (const uint8_t *)src_y + width * height; 157 158 const uint8_t *src_v = 159 (const uint8_t *)src_u + (width / 2) * (height / 2); 160 161 for (size_t y = 0; y < height; ++y) { 162 for (size_t x = 0; x < width; x += 2) { 163 // B = 1.164 * (Y - 16) + 2.018 * (U - 128) 164 // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128) 165 // R = 1.164 * (Y - 16) + 1.596 * (V - 128) 166 167 // B = 298/256 * (Y - 16) + 517/256 * (U - 128) 168 // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128) 169 // R = .................. + 409/256 * (V - 128) 170 171 // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277 172 // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172 173 // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223 174 175 // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534 176 // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432 177 // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481 178 179 // clip range -278 .. 535 180 181 signed y1 = (signed)src_y[x] - 16; 182 signed y2 = (signed)src_y[x + 1] - 16; 183 184 signed u = (signed)src_u[x / 2] - 128; 185 signed v = (signed)src_v[x / 2] - 128; 186 187 signed u_b = u * 517; 188 signed u_g = -u * 100; 189 signed v_g = -v * 208; 190 signed v_r = v * 409; 191 192 signed tmp1 = y1 * 298; 193 signed b1 = (tmp1 + u_b) / 256; 194 signed g1 = (tmp1 + v_g + u_g) / 256; 195 signed r1 = (tmp1 + v_r) / 256; 196 197 signed tmp2 = y2 * 298; 198 signed b2 = (tmp2 + u_b) / 256; 199 signed g2 = (tmp2 + v_g + u_g) / 256; 200 signed r2 = (tmp2 + v_r) / 256; 201 202 uint32_t rgb1 = 203 ((kAdjustedClip[r1] >> 3) << 11) 204 | ((kAdjustedClip[g1] >> 2) << 5) 205 | (kAdjustedClip[b1] >> 3); 206 207 uint32_t rgb2 = 208 ((kAdjustedClip[r2] >> 3) << 11) 209 | ((kAdjustedClip[g2] >> 2) << 5) 210 | (kAdjustedClip[b2] >> 3); 211 212 dst_ptr[x / 2] = (rgb2 << 16) | rgb1; 213 } 214 215 src_y += width; 216 217 if (y & 1) { 218 src_u += width / 2; 219 src_v += width / 2; 220 } 221 222 dst_ptr += dstSkip / 4; 223 } 224 } 225 226 void ColorConverter::convertQCOMYUV420SemiPlanar( 227 size_t width, size_t height, 228 const void *srcBits, size_t srcSkip, 229 void *dstBits, size_t dstSkip) { 230 CHECK_EQ(srcSkip, 0); // Doesn't really make sense for YUV formats. 231 CHECK(dstSkip >= width * 2); 232 CHECK((dstSkip & 3) == 0); 233 234 uint8_t *kAdjustedClip = initClip(); 235 236 uint32_t *dst_ptr = (uint32_t *)dstBits; 237 const uint8_t *src_y = (const uint8_t *)srcBits; 238 239 const uint8_t *src_u = 240 (const uint8_t *)src_y + width * height; 241 242 for (size_t y = 0; y < height; ++y) { 243 for (size_t x = 0; x < width; x += 2) { 244 signed y1 = (signed)src_y[x] - 16; 245 signed y2 = (signed)src_y[x + 1] - 16; 246 247 signed u = (signed)src_u[x & ~1] - 128; 248 signed v = (signed)src_u[(x & ~1) + 1] - 128; 249 250 signed u_b = u * 517; 251 signed u_g = -u * 100; 252 signed v_g = -v * 208; 253 signed v_r = v * 409; 254 255 signed tmp1 = y1 * 298; 256 signed b1 = (tmp1 + u_b) / 256; 257 signed g1 = (tmp1 + v_g + u_g) / 256; 258 signed r1 = (tmp1 + v_r) / 256; 259 260 signed tmp2 = y2 * 298; 261 signed b2 = (tmp2 + u_b) / 256; 262 signed g2 = (tmp2 + v_g + u_g) / 256; 263 signed r2 = (tmp2 + v_r) / 256; 264 265 uint32_t rgb1 = 266 ((kAdjustedClip[b1] >> 3) << 11) 267 | ((kAdjustedClip[g1] >> 2) << 5) 268 | (kAdjustedClip[r1] >> 3); 269 270 uint32_t rgb2 = 271 ((kAdjustedClip[b2] >> 3) << 11) 272 | ((kAdjustedClip[g2] >> 2) << 5) 273 | (kAdjustedClip[r2] >> 3); 274 275 dst_ptr[x / 2] = (rgb2 << 16) | rgb1; 276 } 277 278 src_y += width; 279 280 if (y & 1) { 281 src_u += width; 282 } 283 284 dst_ptr += dstSkip / 4; 285 } 286 } 287 288 void ColorConverter::convertYUV420SemiPlanar( 289 size_t width, size_t height, 290 const void *srcBits, size_t srcSkip, 291 void *dstBits, size_t dstSkip) { 292 CHECK_EQ(srcSkip, 0); // Doesn't really make sense for YUV formats. 293 CHECK(dstSkip >= width * 2); 294 CHECK((dstSkip & 3) == 0); 295 296 uint8_t *kAdjustedClip = initClip(); 297 298 uint32_t *dst_ptr = (uint32_t *)dstBits; 299 const uint8_t *src_y = (const uint8_t *)srcBits; 300 301 const uint8_t *src_u = 302 (const uint8_t *)src_y + width * height; 303 304 for (size_t y = 0; y < height; ++y) { 305 for (size_t x = 0; x < width; x += 2) { 306 signed y1 = (signed)src_y[x] - 16; 307 signed y2 = (signed)src_y[x + 1] - 16; 308 309 signed v = (signed)src_u[x & ~1] - 128; 310 signed u = (signed)src_u[(x & ~1) + 1] - 128; 311 312 signed u_b = u * 517; 313 signed u_g = -u * 100; 314 signed v_g = -v * 208; 315 signed v_r = v * 409; 316 317 signed tmp1 = y1 * 298; 318 signed b1 = (tmp1 + u_b) / 256; 319 signed g1 = (tmp1 + v_g + u_g) / 256; 320 signed r1 = (tmp1 + v_r) / 256; 321 322 signed tmp2 = y2 * 298; 323 signed b2 = (tmp2 + u_b) / 256; 324 signed g2 = (tmp2 + v_g + u_g) / 256; 325 signed r2 = (tmp2 + v_r) / 256; 326 327 uint32_t rgb1 = 328 ((kAdjustedClip[b1] >> 3) << 11) 329 | ((kAdjustedClip[g1] >> 2) << 5) 330 | (kAdjustedClip[r1] >> 3); 331 332 uint32_t rgb2 = 333 ((kAdjustedClip[b2] >> 3) << 11) 334 | ((kAdjustedClip[g2] >> 2) << 5) 335 | (kAdjustedClip[r2] >> 3); 336 337 dst_ptr[x / 2] = (rgb2 << 16) | rgb1; 338 } 339 340 src_y += width; 341 342 if (y & 1) { 343 src_u += width; 344 } 345 346 dst_ptr += dstSkip / 4; 347 } 348 } 349 350 uint8_t *ColorConverter::initClip() { 351 static const signed kClipMin = -278; 352 static const signed kClipMax = 535; 353 354 if (mClip == NULL) { 355 mClip = new uint8_t[kClipMax - kClipMin + 1]; 356 357 for (signed i = kClipMin; i <= kClipMax; ++i) { 358 mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i; 359 } 360 } 361 362 return &mClip[-kClipMin]; 363 } 364 365 } // namespace android 366