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 //#define LOG_NDEBUG 0 18 #define LOG_TAG "ColorConverter" 19 #include <utils/Log.h> 20 21 #include <media/stagefright/foundation/ADebug.h> 22 #include <media/stagefright/foundation/ALooper.h> 23 #include <media/stagefright/ColorConverter.h> 24 #include <media/stagefright/MediaErrors.h> 25 26 #include "libyuv/convert_from.h" 27 #include "libyuv/video_common.h" 28 #include <functional> 29 #include <sys/time.h> 30 31 #define USE_LIBYUV 32 #define PERF_PROFILING 0 33 34 35 #if defined(__aarch64__) || defined(__ARM_NEON__) 36 #define USE_NEON_Y410 1 37 #else 38 #define USE_NEON_Y410 0 39 #endif 40 41 #if USE_NEON_Y410 42 #include <arm_neon.h> 43 #endif 44 45 namespace android { 46 47 ColorConverter::ColorConverter( 48 OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to) 49 : mSrcFormat(from), 50 mDstFormat(to), 51 mClip(NULL) { 52 } 53 54 ColorConverter::~ColorConverter() { 55 delete[] mClip; 56 mClip = NULL; 57 } 58 59 bool ColorConverter::isValid() const { 60 switch (mSrcFormat) { 61 case OMX_COLOR_FormatYUV420Planar16: 62 if (mDstFormat == OMX_COLOR_FormatYUV444Y410) { 63 return true; 64 } 65 // fall-thru 66 case OMX_COLOR_FormatYUV420Planar: 67 return mDstFormat == OMX_COLOR_Format16bitRGB565 68 || mDstFormat == OMX_COLOR_Format32BitRGBA8888 69 || mDstFormat == OMX_COLOR_Format32bitBGRA8888; 70 71 case OMX_COLOR_FormatCbYCrY: 72 case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: 73 case OMX_COLOR_FormatYUV420SemiPlanar: 74 case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: 75 return mDstFormat == OMX_COLOR_Format16bitRGB565; 76 77 default: 78 return false; 79 } 80 } 81 82 bool ColorConverter::isDstRGB() const { 83 return mDstFormat == OMX_COLOR_Format16bitRGB565 84 || mDstFormat == OMX_COLOR_Format32BitRGBA8888 85 || mDstFormat == OMX_COLOR_Format32bitBGRA8888; 86 } 87 88 ColorConverter::BitmapParams::BitmapParams( 89 void *bits, 90 size_t width, size_t height, 91 size_t cropLeft, size_t cropTop, 92 size_t cropRight, size_t cropBottom, 93 OMX_COLOR_FORMATTYPE colorFromat) 94 : mBits(bits), 95 mColorFormat(colorFromat), 96 mWidth(width), 97 mHeight(height), 98 mCropLeft(cropLeft), 99 mCropTop(cropTop), 100 mCropRight(cropRight), 101 mCropBottom(cropBottom) { 102 switch(mColorFormat) { 103 case OMX_COLOR_Format16bitRGB565: 104 mBpp = 2; 105 mStride = 2 * mWidth; 106 break; 107 108 case OMX_COLOR_Format32bitBGRA8888: 109 case OMX_COLOR_Format32BitRGBA8888: 110 case OMX_COLOR_FormatYUV444Y410: 111 mBpp = 4; 112 mStride = 4 * mWidth; 113 break; 114 115 case OMX_COLOR_FormatYUV420Planar16: 116 mBpp = 2; 117 mStride = 2 * mWidth; 118 break; 119 120 case OMX_COLOR_FormatYUV420Planar: 121 case OMX_COLOR_FormatCbYCrY: 122 case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: 123 case OMX_COLOR_FormatYUV420SemiPlanar: 124 case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: 125 mBpp = 1; 126 mStride = mWidth; 127 break; 128 129 default: 130 ALOGE("Unsupported color format %d", mColorFormat); 131 mBpp = 1; 132 mStride = mWidth; 133 break; 134 } 135 } 136 137 size_t ColorConverter::BitmapParams::cropWidth() const { 138 return mCropRight - mCropLeft + 1; 139 } 140 141 size_t ColorConverter::BitmapParams::cropHeight() const { 142 return mCropBottom - mCropTop + 1; 143 } 144 145 status_t ColorConverter::convert( 146 const void *srcBits, 147 size_t srcWidth, size_t srcHeight, 148 size_t srcCropLeft, size_t srcCropTop, 149 size_t srcCropRight, size_t srcCropBottom, 150 void *dstBits, 151 size_t dstWidth, size_t dstHeight, 152 size_t dstCropLeft, size_t dstCropTop, 153 size_t dstCropRight, size_t dstCropBottom) { 154 BitmapParams src( 155 const_cast<void *>(srcBits), 156 srcWidth, srcHeight, 157 srcCropLeft, srcCropTop, srcCropRight, srcCropBottom, mSrcFormat); 158 159 BitmapParams dst( 160 dstBits, 161 dstWidth, dstHeight, 162 dstCropLeft, dstCropTop, dstCropRight, dstCropBottom, mDstFormat); 163 164 if (!((src.mCropLeft & 1) == 0 165 && src.cropWidth() == dst.cropWidth() 166 && src.cropHeight() == dst.cropHeight())) { 167 return ERROR_UNSUPPORTED; 168 } 169 170 status_t err; 171 172 switch (mSrcFormat) { 173 case OMX_COLOR_FormatYUV420Planar: 174 #ifdef USE_LIBYUV 175 err = convertYUV420PlanarUseLibYUV(src, dst); 176 #else 177 err = convertYUV420Planar(src, dst); 178 #endif 179 break; 180 181 case OMX_COLOR_FormatYUV420Planar16: 182 { 183 #if PERF_PROFILING 184 int64_t startTimeUs = ALooper::GetNowUs(); 185 #endif 186 err = convertYUV420Planar16(src, dst); 187 #if PERF_PROFILING 188 int64_t endTimeUs = ALooper::GetNowUs(); 189 ALOGD("convertYUV420Planar16 took %lld us", (long long) (endTimeUs - startTimeUs)); 190 #endif 191 break; 192 } 193 194 case OMX_COLOR_FormatCbYCrY: 195 err = convertCbYCrY(src, dst); 196 break; 197 198 case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: 199 err = convertQCOMYUV420SemiPlanar(src, dst); 200 break; 201 202 case OMX_COLOR_FormatYUV420SemiPlanar: 203 err = convertYUV420SemiPlanar(src, dst); 204 break; 205 206 case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: 207 err = convertTIYUV420PackedSemiPlanar(src, dst); 208 break; 209 210 default: 211 { 212 CHECK(!"Should not be here. Unknown color conversion."); 213 break; 214 } 215 } 216 217 return err; 218 } 219 220 status_t ColorConverter::convertCbYCrY( 221 const BitmapParams &src, const BitmapParams &dst) { 222 // XXX Untested 223 224 uint8_t *kAdjustedClip = initClip(); 225 226 uint16_t *dst_ptr = (uint16_t *)dst.mBits 227 + dst.mCropTop * dst.mWidth + dst.mCropLeft; 228 229 const uint8_t *src_ptr = (const uint8_t *)src.mBits 230 + (src.mCropTop * dst.mWidth + src.mCropLeft) * 2; 231 232 for (size_t y = 0; y < src.cropHeight(); ++y) { 233 for (size_t x = 0; x < src.cropWidth(); x += 2) { 234 signed y1 = (signed)src_ptr[2 * x + 1] - 16; 235 signed y2 = (signed)src_ptr[2 * x + 3] - 16; 236 signed u = (signed)src_ptr[2 * x] - 128; 237 signed v = (signed)src_ptr[2 * x + 2] - 128; 238 239 signed u_b = u * 517; 240 signed u_g = -u * 100; 241 signed v_g = -v * 208; 242 signed v_r = v * 409; 243 244 signed tmp1 = y1 * 298; 245 signed b1 = (tmp1 + u_b) / 256; 246 signed g1 = (tmp1 + v_g + u_g) / 256; 247 signed r1 = (tmp1 + v_r) / 256; 248 249 signed tmp2 = y2 * 298; 250 signed b2 = (tmp2 + u_b) / 256; 251 signed g2 = (tmp2 + v_g + u_g) / 256; 252 signed r2 = (tmp2 + v_r) / 256; 253 254 uint32_t rgb1 = 255 ((kAdjustedClip[r1] >> 3) << 11) 256 | ((kAdjustedClip[g1] >> 2) << 5) 257 | (kAdjustedClip[b1] >> 3); 258 259 uint32_t rgb2 = 260 ((kAdjustedClip[r2] >> 3) << 11) 261 | ((kAdjustedClip[g2] >> 2) << 5) 262 | (kAdjustedClip[b2] >> 3); 263 264 if (x + 1 < src.cropWidth()) { 265 *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1; 266 } else { 267 dst_ptr[x] = rgb1; 268 } 269 } 270 271 src_ptr += src.mWidth * 2; 272 dst_ptr += dst.mWidth; 273 } 274 275 return OK; 276 } 277 278 status_t ColorConverter::convertYUV420PlanarUseLibYUV( 279 const BitmapParams &src, const BitmapParams &dst) { 280 uint8_t *dst_ptr = (uint8_t *)dst.mBits 281 + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp; 282 283 const uint8_t *src_y = 284 (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft; 285 286 const uint8_t *src_u = 287 (const uint8_t *)src.mBits + src.mStride * src.mHeight 288 + (src.mCropTop / 2) * (src.mStride / 2) + (src.mCropLeft / 2); 289 290 const uint8_t *src_v = 291 src_u + (src.mStride / 2) * (src.mHeight / 2); 292 293 switch (mDstFormat) { 294 case OMX_COLOR_Format16bitRGB565: 295 libyuv::I420ToRGB565(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2, 296 (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight()); 297 break; 298 299 case OMX_COLOR_Format32BitRGBA8888: 300 libyuv::ConvertFromI420(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2, 301 (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight(), libyuv::FOURCC_ABGR); 302 break; 303 304 case OMX_COLOR_Format32bitBGRA8888: 305 libyuv::ConvertFromI420(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2, 306 (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight(), libyuv::FOURCC_ARGB); 307 break; 308 309 default: 310 return ERROR_UNSUPPORTED; 311 } 312 313 return OK; 314 } 315 316 std::function<void (void *, void *, void *, size_t, 317 signed *, signed *, signed *, signed *)> 318 getReadFromSrc(OMX_COLOR_FORMATTYPE srcFormat) { 319 switch(srcFormat) { 320 case OMX_COLOR_FormatYUV420Planar: 321 return [](void *src_y, void *src_u, void *src_v, size_t x, 322 signed *y1, signed *y2, signed *u, signed *v) { 323 *y1 = ((uint8_t*)src_y)[x] - 16; 324 *y2 = ((uint8_t*)src_y)[x + 1] - 16; 325 *u = ((uint8_t*)src_u)[x / 2] - 128; 326 *v = ((uint8_t*)src_v)[x / 2] - 128; 327 }; 328 case OMX_COLOR_FormatYUV420Planar16: 329 return [](void *src_y, void *src_u, void *src_v, size_t x, 330 signed *y1, signed *y2, signed *u, signed *v) { 331 *y1 = (signed)(((uint16_t*)src_y)[x] >> 2) - 16; 332 *y2 = (signed)(((uint16_t*)src_y)[x + 1] >> 2) - 16; 333 *u = (signed)(((uint16_t*)src_u)[x / 2] >> 2) - 128; 334 *v = (signed)(((uint16_t*)src_v)[x / 2] >> 2) - 128; 335 }; 336 default: 337 TRESPASS(); 338 } 339 return nullptr; 340 } 341 342 std::function<void (void *, bool, signed, signed, signed, signed, signed, signed)> 343 getWriteToDst(OMX_COLOR_FORMATTYPE dstFormat, uint8_t *kAdjustedClip) { 344 switch (dstFormat) { 345 case OMX_COLOR_Format16bitRGB565: 346 { 347 return [kAdjustedClip](void *dst_ptr, bool uncropped, 348 signed r1, signed g1, signed b1, 349 signed r2, signed g2, signed b2) { 350 uint32_t rgb1 = 351 ((kAdjustedClip[r1] >> 3) << 11) 352 | ((kAdjustedClip[g1] >> 2) << 5) 353 | (kAdjustedClip[b1] >> 3); 354 355 if (uncropped) { 356 uint32_t rgb2 = 357 ((kAdjustedClip[r2] >> 3) << 11) 358 | ((kAdjustedClip[g2] >> 2) << 5) 359 | (kAdjustedClip[b2] >> 3); 360 361 *(uint32_t *)dst_ptr = (rgb2 << 16) | rgb1; 362 } else { 363 *(uint16_t *)dst_ptr = rgb1; 364 } 365 }; 366 } 367 case OMX_COLOR_Format32BitRGBA8888: 368 { 369 return [kAdjustedClip](void *dst_ptr, bool uncropped, 370 signed r1, signed g1, signed b1, 371 signed r2, signed g2, signed b2) { 372 ((uint32_t *)dst_ptr)[0] = 373 (kAdjustedClip[r1]) 374 | (kAdjustedClip[g1] << 8) 375 | (kAdjustedClip[b1] << 16) 376 | (0xFF << 24); 377 378 if (uncropped) { 379 ((uint32_t *)dst_ptr)[1] = 380 (kAdjustedClip[r2]) 381 | (kAdjustedClip[g2] << 8) 382 | (kAdjustedClip[b2] << 16) 383 | (0xFF << 24); 384 } 385 }; 386 } 387 case OMX_COLOR_Format32bitBGRA8888: 388 { 389 return [kAdjustedClip](void *dst_ptr, bool uncropped, 390 signed r1, signed g1, signed b1, 391 signed r2, signed g2, signed b2) { 392 ((uint32_t *)dst_ptr)[0] = 393 (kAdjustedClip[b1]) 394 | (kAdjustedClip[g1] << 8) 395 | (kAdjustedClip[r1] << 16) 396 | (0xFF << 24); 397 398 if (uncropped) { 399 ((uint32_t *)dst_ptr)[1] = 400 (kAdjustedClip[b2]) 401 | (kAdjustedClip[g2] << 8) 402 | (kAdjustedClip[r2] << 16) 403 | (0xFF << 24); 404 } 405 }; 406 } 407 default: 408 TRESPASS(); 409 } 410 return nullptr; 411 } 412 413 status_t ColorConverter::convertYUV420Planar( 414 const BitmapParams &src, const BitmapParams &dst) { 415 uint8_t *kAdjustedClip = initClip(); 416 417 auto readFromSrc = getReadFromSrc(mSrcFormat); 418 auto writeToDst = getWriteToDst(mDstFormat, kAdjustedClip); 419 420 uint8_t *dst_ptr = (uint8_t *)dst.mBits 421 + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp; 422 423 uint8_t *src_y = (uint8_t *)src.mBits 424 + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp; 425 426 uint8_t *src_u = (uint8_t *)src.mBits + src.mStride * src.mHeight 427 + (src.mCropTop / 2) * (src.mStride / 2) + src.mCropLeft / 2 * src.mBpp; 428 429 uint8_t *src_v = src_u + (src.mStride / 2) * (src.mHeight / 2); 430 431 for (size_t y = 0; y < src.cropHeight(); ++y) { 432 for (size_t x = 0; x < src.cropWidth(); x += 2) { 433 // B = 1.164 * (Y - 16) + 2.018 * (U - 128) 434 // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128) 435 // R = 1.164 * (Y - 16) + 1.596 * (V - 128) 436 437 // B = 298/256 * (Y - 16) + 517/256 * (U - 128) 438 // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128) 439 // R = .................. + 409/256 * (V - 128) 440 441 // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277 442 // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172 443 // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223 444 445 // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534 446 // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432 447 // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481 448 449 // clip range -278 .. 535 450 451 signed y1, y2, u, v; 452 readFromSrc(src_y, src_u, src_v, x, &y1, &y2, &u, &v); 453 454 signed u_b = u * 517; 455 signed u_g = -u * 100; 456 signed v_g = -v * 208; 457 signed v_r = v * 409; 458 459 signed tmp1 = y1 * 298; 460 signed b1 = (tmp1 + u_b) / 256; 461 signed g1 = (tmp1 + v_g + u_g) / 256; 462 signed r1 = (tmp1 + v_r) / 256; 463 464 signed tmp2 = y2 * 298; 465 signed b2 = (tmp2 + u_b) / 256; 466 signed g2 = (tmp2 + v_g + u_g) / 256; 467 signed r2 = (tmp2 + v_r) / 256; 468 469 bool uncropped = x + 1 < src.cropWidth(); 470 writeToDst(dst_ptr + x * dst.mBpp, uncropped, r1, g1, b1, r2, g2, b2); 471 } 472 473 src_y += src.mStride; 474 475 if (y & 1) { 476 src_u += src.mStride / 2; 477 src_v += src.mStride / 2; 478 } 479 480 dst_ptr += dst.mStride; 481 } 482 483 return OK; 484 } 485 486 status_t ColorConverter::convertYUV420Planar16( 487 const BitmapParams &src, const BitmapParams &dst) { 488 if (mDstFormat == OMX_COLOR_FormatYUV444Y410) { 489 return convertYUV420Planar16ToY410(src, dst); 490 } 491 492 return convertYUV420Planar(src, dst); 493 } 494 495 /* 496 * Pack 10-bit YUV into RGBA_1010102. 497 * 498 * Media sends 10-bit YUV in a RGBA_1010102 format buffer. SF will handle 499 * the conversion to RGB using RenderEngine fallback. 500 * 501 * We do not perform a YUV->RGB conversion here, however the conversion with 502 * BT2020 to Full range is below for reference: 503 * 504 * B = 1.168 *(Y - 64) + 2.148 *(U - 512) 505 * G = 1.168 *(Y - 64) - 0.652 *(V - 512) - 0.188 *(U - 512) 506 * R = 1.168 *(Y - 64) + 1.683 *(V - 512) 507 * 508 * B = 1196/1024 *(Y - 64) + 2200/1024 *(U - 512) 509 * G = .................... - 668/1024 *(V - 512) - 192/1024 *(U - 512) 510 * R = .................... + 1723/1024 *(V - 512) 511 * 512 * min_B = (1196 *(- 64) + 2200 *(- 512)) / 1024 = -1175 513 * min_G = (1196 *(- 64) - 668 *(1023 - 512) - 192 *(1023 - 512)) / 1024 = -504 514 * min_R = (1196 *(- 64) + 1723 *(- 512)) / 1024 = -937 515 * 516 * max_B = (1196 *(1023 - 64) + 2200 *(1023 - 512)) / 1024 = 2218 517 * max_G = (1196 *(1023 - 64) - 668 *(- 512) - 192 *(- 512)) / 1024 = 1551 518 * max_R = (1196 *(1023 - 64) + 1723 *(1023 - 512)) / 1024 = 1980 519 * 520 * clip range -1175 .. 2218 521 * 522 */ 523 524 #if !USE_NEON_Y410 525 526 status_t ColorConverter::convertYUV420Planar16ToY410( 527 const BitmapParams &src, const BitmapParams &dst) { 528 uint8_t *dst_ptr = (uint8_t *)dst.mBits 529 + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp; 530 531 const uint8_t *src_y = 532 (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp; 533 534 const uint8_t *src_u = 535 (const uint8_t *)src.mBits + src.mStride * src.mHeight 536 + (src.mCropTop / 2) * (src.mStride / 2) + (src.mCropLeft / 2) * src.mBpp; 537 538 const uint8_t *src_v = 539 src_u + (src.mStride / 2) * (src.mHeight / 2); 540 541 // Converting two lines at a time, slightly faster 542 for (size_t y = 0; y < src.cropHeight(); y += 2) { 543 uint32_t *dst_top = (uint32_t *) dst_ptr; 544 uint32_t *dst_bot = (uint32_t *) (dst_ptr + dst.mStride); 545 uint16_t *ptr_ytop = (uint16_t*) src_y; 546 uint16_t *ptr_ybot = (uint16_t*) (src_y + src.mStride); 547 uint16_t *ptr_u = (uint16_t*) src_u; 548 uint16_t *ptr_v = (uint16_t*) src_v; 549 550 uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1; 551 size_t x = 0; 552 for (; x < src.cropWidth() - 3; x += 4) { 553 u01 = *((uint32_t*)ptr_u); ptr_u += 2; 554 v01 = *((uint32_t*)ptr_v); ptr_v += 2; 555 556 y01 = *((uint32_t*)ptr_ytop); ptr_ytop += 2; 557 y23 = *((uint32_t*)ptr_ytop); ptr_ytop += 2; 558 y45 = *((uint32_t*)ptr_ybot); ptr_ybot += 2; 559 y67 = *((uint32_t*)ptr_ybot); ptr_ybot += 2; 560 561 uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20); 562 uv1 = (u01 >> 16) | ((v01 >> 16) << 20); 563 564 *dst_top++ = ((y01 & 0x3FF) << 10) | uv0; 565 *dst_top++ = ((y01 >> 16) << 10) | uv0; 566 *dst_top++ = ((y23 & 0x3FF) << 10) | uv1; 567 *dst_top++ = ((y23 >> 16) << 10) | uv1; 568 569 *dst_bot++ = ((y45 & 0x3FF) << 10) | uv0; 570 *dst_bot++ = ((y45 >> 16) << 10) | uv0; 571 *dst_bot++ = ((y67 & 0x3FF) << 10) | uv1; 572 *dst_bot++ = ((y67 >> 16) << 10) | uv1; 573 } 574 575 // There should be at most 2 more pixels to process. Note that we don't 576 // need to consider odd case as the buffer is always aligned to even. 577 if (x < src.cropWidth()) { 578 u01 = *ptr_u; 579 v01 = *ptr_v; 580 y01 = *((uint32_t*)ptr_ytop); 581 y45 = *((uint32_t*)ptr_ybot); 582 uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20); 583 *dst_top++ = ((y01 & 0x3FF) << 10) | uv0; 584 *dst_top++ = ((y01 >> 16) << 10) | uv0; 585 *dst_bot++ = ((y45 & 0x3FF) << 10) | uv0; 586 *dst_bot++ = ((y45 >> 16) << 10) | uv0; 587 } 588 589 src_y += src.mStride * 2; 590 src_u += src.mStride / 2; 591 src_v += src.mStride / 2; 592 dst_ptr += dst.mStride * 2; 593 } 594 595 return OK; 596 } 597 598 #else 599 600 status_t ColorConverter::convertYUV420Planar16ToY410( 601 const BitmapParams &src, const BitmapParams &dst) { 602 uint8_t *out = (uint8_t *)dst.mBits 603 + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp; 604 605 const uint8_t *src_y = 606 (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp; 607 608 const uint8_t *src_u = 609 (const uint8_t *)src.mBits + src.mStride * src.mHeight 610 + (src.mCropTop / 2) * (src.mStride / 2) + (src.mCropLeft / 2) * src.mBpp; 611 612 const uint8_t *src_v = 613 src_u + (src.mStride / 2) * (src.mHeight / 2); 614 615 for (size_t y = 0; y < src.cropHeight(); y++) { 616 uint16_t *ptr_y = (uint16_t*) src_y; 617 uint16_t *ptr_u = (uint16_t*) src_u; 618 uint16_t *ptr_v = (uint16_t*) src_v; 619 uint32_t *ptr_out = (uint32_t *) out; 620 621 // Process 16-pixel at a time. 622 uint32_t *ptr_limit = ptr_out + (src.cropWidth() & ~15); 623 while (ptr_out < ptr_limit) { 624 uint16x4_t u0123 = vld1_u16(ptr_u); ptr_u += 4; 625 uint16x4_t u4567 = vld1_u16(ptr_u); ptr_u += 4; 626 uint16x4_t v0123 = vld1_u16(ptr_v); ptr_v += 4; 627 uint16x4_t v4567 = vld1_u16(ptr_v); ptr_v += 4; 628 uint16x4_t y0123 = vld1_u16(ptr_y); ptr_y += 4; 629 uint16x4_t y4567 = vld1_u16(ptr_y); ptr_y += 4; 630 uint16x4_t y89ab = vld1_u16(ptr_y); ptr_y += 4; 631 uint16x4_t ycdef = vld1_u16(ptr_y); ptr_y += 4; 632 633 uint32x2_t uvtempl; 634 uint32x4_t uvtempq; 635 636 uvtempq = vaddw_u16(vshll_n_u16(v0123, 20), u0123); 637 638 uvtempl = vget_low_u32(uvtempq); 639 uint32x4_t uv0011 = vreinterpretq_u32_u64( 640 vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl)); 641 642 uvtempl = vget_high_u32(uvtempq); 643 uint32x4_t uv2233 = vreinterpretq_u32_u64( 644 vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl)); 645 646 uvtempq = vaddw_u16(vshll_n_u16(v4567, 20), u4567); 647 648 uvtempl = vget_low_u32(uvtempq); 649 uint32x4_t uv4455 = vreinterpretq_u32_u64( 650 vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl)); 651 652 uvtempl = vget_high_u32(uvtempq); 653 uint32x4_t uv6677 = vreinterpretq_u32_u64( 654 vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl)); 655 656 uint32x4_t dsttemp; 657 658 dsttemp = vorrq_u32(uv0011, vshll_n_u16(y0123, 10)); 659 vst1q_u32(ptr_out, dsttemp); ptr_out += 4; 660 661 dsttemp = vorrq_u32(uv2233, vshll_n_u16(y4567, 10)); 662 vst1q_u32(ptr_out, dsttemp); ptr_out += 4; 663 664 dsttemp = vorrq_u32(uv4455, vshll_n_u16(y89ab, 10)); 665 vst1q_u32(ptr_out, dsttemp); ptr_out += 4; 666 667 dsttemp = vorrq_u32(uv6677, vshll_n_u16(ycdef, 10)); 668 vst1q_u32(ptr_out, dsttemp); ptr_out += 4; 669 } 670 671 src_y += src.mStride; 672 if (y & 1) { 673 src_u += src.mStride / 2; 674 src_v += src.mStride / 2; 675 } 676 out += dst.mStride; 677 } 678 679 // Process the left-overs out-of-loop, 2-pixel at a time. Note that we don't 680 // need to consider odd case as the buffer is always aligned to even. 681 if (src.cropWidth() & 15) { 682 size_t xstart = (src.cropWidth() & ~15); 683 684 uint8_t *out = (uint8_t *)dst.mBits + dst.mCropTop * dst.mStride 685 + (dst.mCropLeft + xstart) * dst.mBpp; 686 687 const uint8_t *src_y = (const uint8_t *)src.mBits + src.mCropTop * src.mStride 688 + (src.mCropLeft + xstart) * src.mBpp; 689 690 const uint8_t *src_u = (const uint8_t *)src.mBits + src.mStride * src.mHeight 691 + (src.mCropTop / 2) * (src.mStride / 2) 692 + ((src.mCropLeft + xstart) / 2) * src.mBpp; 693 694 const uint8_t *src_v = src_u + (src.mStride / 2) * (src.mHeight / 2); 695 696 for (size_t y = 0; y < src.cropHeight(); y++) { 697 uint16_t *ptr_y = (uint16_t*) src_y; 698 uint16_t *ptr_u = (uint16_t*) src_u; 699 uint16_t *ptr_v = (uint16_t*) src_v; 700 uint32_t *ptr_out = (uint32_t *) out; 701 for (size_t x = xstart; x < src.cropWidth(); x += 2) { 702 uint16_t u = *ptr_u++; 703 uint16_t v = *ptr_v++; 704 uint32_t y01 = *((uint32_t*)ptr_y); ptr_y += 2; 705 uint32_t uv = u | (((uint32_t)v) << 20); 706 *ptr_out++ = ((y01 & 0x3FF) << 10) | uv; 707 *ptr_out++ = ((y01 >> 16) << 10) | uv; 708 } 709 src_y += src.mStride; 710 if (y & 1) { 711 src_u += src.mStride / 2; 712 src_v += src.mStride / 2; 713 } 714 out += dst.mStride; 715 } 716 } 717 718 return OK; 719 } 720 721 #endif // USE_NEON_Y410 722 723 status_t ColorConverter::convertQCOMYUV420SemiPlanar( 724 const BitmapParams &src, const BitmapParams &dst) { 725 uint8_t *kAdjustedClip = initClip(); 726 727 uint16_t *dst_ptr = (uint16_t *)dst.mBits 728 + dst.mCropTop * dst.mWidth + dst.mCropLeft; 729 730 const uint8_t *src_y = 731 (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft; 732 733 const uint8_t *src_u = 734 (const uint8_t *)src_y + src.mWidth * src.mHeight 735 + src.mCropTop * src.mWidth + src.mCropLeft; 736 737 for (size_t y = 0; y < src.cropHeight(); ++y) { 738 for (size_t x = 0; x < src.cropWidth(); x += 2) { 739 signed y1 = (signed)src_y[x] - 16; 740 signed y2 = (signed)src_y[x + 1] - 16; 741 742 signed u = (signed)src_u[x & ~1] - 128; 743 signed v = (signed)src_u[(x & ~1) + 1] - 128; 744 745 signed u_b = u * 517; 746 signed u_g = -u * 100; 747 signed v_g = -v * 208; 748 signed v_r = v * 409; 749 750 signed tmp1 = y1 * 298; 751 signed b1 = (tmp1 + u_b) / 256; 752 signed g1 = (tmp1 + v_g + u_g) / 256; 753 signed r1 = (tmp1 + v_r) / 256; 754 755 signed tmp2 = y2 * 298; 756 signed b2 = (tmp2 + u_b) / 256; 757 signed g2 = (tmp2 + v_g + u_g) / 256; 758 signed r2 = (tmp2 + v_r) / 256; 759 760 uint32_t rgb1 = 761 ((kAdjustedClip[b1] >> 3) << 11) 762 | ((kAdjustedClip[g1] >> 2) << 5) 763 | (kAdjustedClip[r1] >> 3); 764 765 uint32_t rgb2 = 766 ((kAdjustedClip[b2] >> 3) << 11) 767 | ((kAdjustedClip[g2] >> 2) << 5) 768 | (kAdjustedClip[r2] >> 3); 769 770 if (x + 1 < src.cropWidth()) { 771 *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1; 772 } else { 773 dst_ptr[x] = rgb1; 774 } 775 } 776 777 src_y += src.mWidth; 778 779 if (y & 1) { 780 src_u += src.mWidth; 781 } 782 783 dst_ptr += dst.mWidth; 784 } 785 786 return OK; 787 } 788 789 status_t ColorConverter::convertYUV420SemiPlanar( 790 const BitmapParams &src, const BitmapParams &dst) { 791 // XXX Untested 792 793 uint8_t *kAdjustedClip = initClip(); 794 795 uint16_t *dst_ptr = (uint16_t *)dst.mBits 796 + dst.mCropTop * dst.mWidth + dst.mCropLeft; 797 798 const uint8_t *src_y = 799 (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft; 800 801 const uint8_t *src_u = 802 (const uint8_t *)src_y + src.mWidth * src.mHeight 803 + src.mCropTop * src.mWidth + src.mCropLeft; 804 805 for (size_t y = 0; y < src.cropHeight(); ++y) { 806 for (size_t x = 0; x < src.cropWidth(); x += 2) { 807 signed y1 = (signed)src_y[x] - 16; 808 signed y2 = (signed)src_y[x + 1] - 16; 809 810 signed v = (signed)src_u[x & ~1] - 128; 811 signed u = (signed)src_u[(x & ~1) + 1] - 128; 812 813 signed u_b = u * 517; 814 signed u_g = -u * 100; 815 signed v_g = -v * 208; 816 signed v_r = v * 409; 817 818 signed tmp1 = y1 * 298; 819 signed b1 = (tmp1 + u_b) / 256; 820 signed g1 = (tmp1 + v_g + u_g) / 256; 821 signed r1 = (tmp1 + v_r) / 256; 822 823 signed tmp2 = y2 * 298; 824 signed b2 = (tmp2 + u_b) / 256; 825 signed g2 = (tmp2 + v_g + u_g) / 256; 826 signed r2 = (tmp2 + v_r) / 256; 827 828 uint32_t rgb1 = 829 ((kAdjustedClip[b1] >> 3) << 11) 830 | ((kAdjustedClip[g1] >> 2) << 5) 831 | (kAdjustedClip[r1] >> 3); 832 833 uint32_t rgb2 = 834 ((kAdjustedClip[b2] >> 3) << 11) 835 | ((kAdjustedClip[g2] >> 2) << 5) 836 | (kAdjustedClip[r2] >> 3); 837 838 if (x + 1 < src.cropWidth()) { 839 *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1; 840 } else { 841 dst_ptr[x] = rgb1; 842 } 843 } 844 845 src_y += src.mWidth; 846 847 if (y & 1) { 848 src_u += src.mWidth; 849 } 850 851 dst_ptr += dst.mWidth; 852 } 853 854 return OK; 855 } 856 857 status_t ColorConverter::convertTIYUV420PackedSemiPlanar( 858 const BitmapParams &src, const BitmapParams &dst) { 859 uint8_t *kAdjustedClip = initClip(); 860 861 uint16_t *dst_ptr = (uint16_t *)dst.mBits 862 + dst.mCropTop * dst.mWidth + dst.mCropLeft; 863 864 const uint8_t *src_y = 865 (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft; 866 867 const uint8_t *src_u = 868 (const uint8_t *)src_y + src.mWidth * (src.mHeight - src.mCropTop / 2); 869 870 for (size_t y = 0; y < src.cropHeight(); ++y) { 871 for (size_t x = 0; x < src.cropWidth(); x += 2) { 872 signed y1 = (signed)src_y[x] - 16; 873 signed y2 = (signed)src_y[x + 1] - 16; 874 875 signed u = (signed)src_u[x & ~1] - 128; 876 signed v = (signed)src_u[(x & ~1) + 1] - 128; 877 878 signed u_b = u * 517; 879 signed u_g = -u * 100; 880 signed v_g = -v * 208; 881 signed v_r = v * 409; 882 883 signed tmp1 = y1 * 298; 884 signed b1 = (tmp1 + u_b) / 256; 885 signed g1 = (tmp1 + v_g + u_g) / 256; 886 signed r1 = (tmp1 + v_r) / 256; 887 888 signed tmp2 = y2 * 298; 889 signed b2 = (tmp2 + u_b) / 256; 890 signed g2 = (tmp2 + v_g + u_g) / 256; 891 signed r2 = (tmp2 + v_r) / 256; 892 893 uint32_t rgb1 = 894 ((kAdjustedClip[r1] >> 3) << 11) 895 | ((kAdjustedClip[g1] >> 2) << 5) 896 | (kAdjustedClip[b1] >> 3); 897 898 uint32_t rgb2 = 899 ((kAdjustedClip[r2] >> 3) << 11) 900 | ((kAdjustedClip[g2] >> 2) << 5) 901 | (kAdjustedClip[b2] >> 3); 902 903 if (x + 1 < src.cropWidth()) { 904 *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1; 905 } else { 906 dst_ptr[x] = rgb1; 907 } 908 } 909 910 src_y += src.mWidth; 911 912 if (y & 1) { 913 src_u += src.mWidth; 914 } 915 916 dst_ptr += dst.mWidth; 917 } 918 919 return OK; 920 } 921 922 uint8_t *ColorConverter::initClip() { 923 static const signed kClipMin = -278; 924 static const signed kClipMax = 535; 925 926 if (mClip == NULL) { 927 mClip = new uint8_t[kClipMax - kClipMin + 1]; 928 929 for (signed i = kClipMin; i <= kClipMax; ++i) { 930 mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i; 931 } 932 } 933 934 return &mClip[-kClipMin]; 935 } 936 937 } // namespace android 938