Home | History | Annotate | Download | only in colorconversion
      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