12a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber/*
22a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber * Copyright (C) 2009 The Android Open Source Project
32a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber *
42a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
52a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber * you may not use this file except in compliance with the License.
62a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber * You may obtain a copy of the License at
72a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber *
82a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
92a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber *
102a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber * Unless required by applicable law or agreed to in writing, software
112a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
122a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber * See the License for the specific language governing permissions and
142a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber * limitations under the License.
152a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber */
162a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
173571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber//#define LOG_NDEBUG 0
183571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber#define LOG_TAG "ColorConverter"
193571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber#include <utils/Log.h>
203571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber
21f1d5aa162c02a16b7195a43a9bcea4d592600ac4James Dong#include <media/stagefright/foundation/ADebug.h>
222d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#include <media/stagefright/foundation/ALooper.h>
232a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber#include <media/stagefright/ColorConverter.h>
241472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber#include <media/stagefright/MediaErrors.h>
252a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
26d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang#include "libyuv/convert_from.h"
27026d520295b52d136a6962a05882a696fe620725Chong Zhang#include "libyuv/video_common.h"
284fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang#include <functional>
292d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#include <sys/time.h>
302d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
31d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang#define USE_LIBYUV
322d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#define PERF_PROFILING 0
332d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
342d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
352d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#if defined(__aarch64__) || defined(__ARM_NEON__)
362d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#define USE_NEON_Y410 1
372d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#else
382d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#define USE_NEON_Y410 0
392d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#endif
402d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
412d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#if USE_NEON_Y410
422d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#include <arm_neon.h>
432d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#endif
44d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang
452a4a7d5af053a17586a262a1267ba993e31790f1Andreas Hubernamespace android {
462a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
472a4a7d5af053a17586a262a1267ba993e31790f1Andreas HuberColorConverter::ColorConverter(
482a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to)
492a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    : mSrcFormat(from),
502a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber      mDstFormat(to),
512a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber      mClip(NULL) {
522a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
532a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
542a4a7d5af053a17586a262a1267ba993e31790f1Andreas HuberColorConverter::~ColorConverter() {
552a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    delete[] mClip;
562a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    mClip = NULL;
572a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
582a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
592a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huberbool ColorConverter::isValid() const {
602a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    switch (mSrcFormat) {
614fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        case OMX_COLOR_FormatYUV420Planar16:
624fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            if (mDstFormat == OMX_COLOR_FormatYUV444Y410) {
634fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                return true;
644fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            }
654fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            // fall-thru
662a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        case OMX_COLOR_FormatYUV420Planar:
67026d520295b52d136a6962a05882a696fe620725Chong Zhang            return mDstFormat == OMX_COLOR_Format16bitRGB565
68026d520295b52d136a6962a05882a696fe620725Chong Zhang                    || mDstFormat == OMX_COLOR_Format32BitRGBA8888
69026d520295b52d136a6962a05882a696fe620725Chong Zhang                    || mDstFormat == OMX_COLOR_Format32bitBGRA8888;
70026d520295b52d136a6962a05882a696fe620725Chong Zhang
712a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        case OMX_COLOR_FormatCbYCrY:
722a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
731c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber        case OMX_COLOR_FormatYUV420SemiPlanar:
74cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan        case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
75026d520295b52d136a6962a05882a696fe620725Chong Zhang            return mDstFormat == OMX_COLOR_Format16bitRGB565;
762a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
772a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        default:
782a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            return false;
792a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    }
802a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
812a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
825343bc86119430e55fe43e132242291a74164f27Chong Zhangbool ColorConverter::isDstRGB() const {
835343bc86119430e55fe43e132242291a74164f27Chong Zhang    return mDstFormat == OMX_COLOR_Format16bitRGB565
845343bc86119430e55fe43e132242291a74164f27Chong Zhang            || mDstFormat == OMX_COLOR_Format32BitRGBA8888
855343bc86119430e55fe43e132242291a74164f27Chong Zhang            || mDstFormat == OMX_COLOR_Format32bitBGRA8888;
865343bc86119430e55fe43e132242291a74164f27Chong Zhang}
875343bc86119430e55fe43e132242291a74164f27Chong Zhang
88f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas HuberColorConverter::BitmapParams::BitmapParams(
89f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        void *bits,
902a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        size_t width, size_t height,
91f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t cropLeft, size_t cropTop,
92026d520295b52d136a6962a05882a696fe620725Chong Zhang        size_t cropRight, size_t cropBottom,
93026d520295b52d136a6962a05882a696fe620725Chong Zhang        OMX_COLOR_FORMATTYPE colorFromat)
94f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    : mBits(bits),
95026d520295b52d136a6962a05882a696fe620725Chong Zhang      mColorFormat(colorFromat),
96f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber      mWidth(width),
97f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber      mHeight(height),
98f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber      mCropLeft(cropLeft),
99f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber      mCropTop(cropTop),
100f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber      mCropRight(cropRight),
101f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber      mCropBottom(cropBottom) {
102026d520295b52d136a6962a05882a696fe620725Chong Zhang    switch(mColorFormat) {
103026d520295b52d136a6962a05882a696fe620725Chong Zhang    case OMX_COLOR_Format16bitRGB565:
104026d520295b52d136a6962a05882a696fe620725Chong Zhang        mBpp = 2;
105026d520295b52d136a6962a05882a696fe620725Chong Zhang        mStride = 2 * mWidth;
106026d520295b52d136a6962a05882a696fe620725Chong Zhang        break;
107026d520295b52d136a6962a05882a696fe620725Chong Zhang
108026d520295b52d136a6962a05882a696fe620725Chong Zhang    case OMX_COLOR_Format32bitBGRA8888:
109026d520295b52d136a6962a05882a696fe620725Chong Zhang    case OMX_COLOR_Format32BitRGBA8888:
1105343bc86119430e55fe43e132242291a74164f27Chong Zhang    case OMX_COLOR_FormatYUV444Y410:
111026d520295b52d136a6962a05882a696fe620725Chong Zhang        mBpp = 4;
112026d520295b52d136a6962a05882a696fe620725Chong Zhang        mStride = 4 * mWidth;
113026d520295b52d136a6962a05882a696fe620725Chong Zhang        break;
114026d520295b52d136a6962a05882a696fe620725Chong Zhang
1152d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    case OMX_COLOR_FormatYUV420Planar16:
1162d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        mBpp = 2;
1172d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        mStride = 2 * mWidth;
1182d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        break;
1192d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
120026d520295b52d136a6962a05882a696fe620725Chong Zhang    case OMX_COLOR_FormatYUV420Planar:
121026d520295b52d136a6962a05882a696fe620725Chong Zhang    case OMX_COLOR_FormatCbYCrY:
122026d520295b52d136a6962a05882a696fe620725Chong Zhang    case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
123026d520295b52d136a6962a05882a696fe620725Chong Zhang    case OMX_COLOR_FormatYUV420SemiPlanar:
124026d520295b52d136a6962a05882a696fe620725Chong Zhang    case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
125026d520295b52d136a6962a05882a696fe620725Chong Zhang        mBpp = 1;
126026d520295b52d136a6962a05882a696fe620725Chong Zhang        mStride = mWidth;
127026d520295b52d136a6962a05882a696fe620725Chong Zhang        break;
128026d520295b52d136a6962a05882a696fe620725Chong Zhang
129026d520295b52d136a6962a05882a696fe620725Chong Zhang    default:
130026d520295b52d136a6962a05882a696fe620725Chong Zhang        ALOGE("Unsupported color format %d", mColorFormat);
131026d520295b52d136a6962a05882a696fe620725Chong Zhang        mBpp = 1;
132026d520295b52d136a6962a05882a696fe620725Chong Zhang        mStride = mWidth;
133026d520295b52d136a6962a05882a696fe620725Chong Zhang        break;
134026d520295b52d136a6962a05882a696fe620725Chong Zhang    }
135f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber}
136f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
137f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Hubersize_t ColorConverter::BitmapParams::cropWidth() const {
138f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    return mCropRight - mCropLeft + 1;
139f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber}
140f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
141f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Hubersize_t ColorConverter::BitmapParams::cropHeight() const {
142f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    return mCropBottom - mCropTop + 1;
143f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber}
144f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
1451472eb39f7516faa26de200d8592464c8aaac38eAndreas Huberstatus_t ColorConverter::convert(
146f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        const void *srcBits,
147f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t srcWidth, size_t srcHeight,
148f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t srcCropLeft, size_t srcCropTop,
149f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t srcCropRight, size_t srcCropBottom,
150f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        void *dstBits,
151f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t dstWidth, size_t dstHeight,
152f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t dstCropLeft, size_t dstCropTop,
153f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t dstCropRight, size_t dstCropBottom) {
154f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    BitmapParams src(
155f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            const_cast<void *>(srcBits),
156f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            srcWidth, srcHeight,
157026d520295b52d136a6962a05882a696fe620725Chong Zhang            srcCropLeft, srcCropTop, srcCropRight, srcCropBottom, mSrcFormat);
158f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
159f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    BitmapParams dst(
160f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            dstBits,
161f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            dstWidth, dstHeight,
162026d520295b52d136a6962a05882a696fe620725Chong Zhang            dstCropLeft, dstCropTop, dstCropRight, dstCropBottom, mDstFormat);
163f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
164d3e0d861aa68a7ef129fe228595bff734448ebc8Chong Zhang    if (!((src.mCropLeft & 1) == 0
165d3e0d861aa68a7ef129fe228595bff734448ebc8Chong Zhang        && src.cropWidth() == dst.cropWidth()
166d3e0d861aa68a7ef129fe228595bff734448ebc8Chong Zhang        && src.cropHeight() == dst.cropHeight())) {
167d3e0d861aa68a7ef129fe228595bff734448ebc8Chong Zhang        return ERROR_UNSUPPORTED;
168d3e0d861aa68a7ef129fe228595bff734448ebc8Chong Zhang    }
169d3e0d861aa68a7ef129fe228595bff734448ebc8Chong Zhang
1701472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    status_t err;
1711472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber
1722a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    switch (mSrcFormat) {
1732a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        case OMX_COLOR_FormatYUV420Planar:
174d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang#ifdef USE_LIBYUV
175d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang            err = convertYUV420PlanarUseLibYUV(src, dst);
176d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang#else
1771472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber            err = convertYUV420Planar(src, dst);
178d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang#endif
1792a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            break;
1802a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1812d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        case OMX_COLOR_FormatYUV420Planar16:
1822d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        {
1832d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#if PERF_PROFILING
1842d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            int64_t startTimeUs = ALooper::GetNowUs();
1852d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#endif
1862d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            err = convertYUV420Planar16(src, dst);
1872d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#if PERF_PROFILING
1882d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            int64_t endTimeUs = ALooper::GetNowUs();
1892d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            ALOGD("convertYUV420Planar16 took %lld us", (long long) (endTimeUs - startTimeUs));
1902d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#endif
1912d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            break;
1922d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        }
1932d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
1942a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        case OMX_COLOR_FormatCbYCrY:
1951472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber            err = convertCbYCrY(src, dst);
1962a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            break;
1972a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1982a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
1991472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber            err = convertQCOMYUV420SemiPlanar(src, dst);
2002a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            break;
2012a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2021c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber        case OMX_COLOR_FormatYUV420SemiPlanar:
2031472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber            err = convertYUV420SemiPlanar(src, dst);
2041c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            break;
2051c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
206cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan        case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
207cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            err = convertTIYUV420PackedSemiPlanar(src, dst);
208cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            break;
209cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
2102a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        default:
2112a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        {
2122a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            CHECK(!"Should not be here. Unknown color conversion.");
2132a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            break;
2142a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        }
2152a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    }
2161472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber
2171472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    return err;
2182a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
2192a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2201472eb39f7516faa26de200d8592464c8aaac38eAndreas Huberstatus_t ColorConverter::convertCbYCrY(
221f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        const BitmapParams &src, const BitmapParams &dst) {
222f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    // XXX Untested
2232a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2242a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    uint8_t *kAdjustedClip = initClip();
2252a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2264e260ab948787c2a814543077832847deae890fdJames Dong    uint16_t *dst_ptr = (uint16_t *)dst.mBits
2274e260ab948787c2a814543077832847deae890fdJames Dong        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
2282a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
229f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    const uint8_t *src_ptr = (const uint8_t *)src.mBits
230f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        + (src.mCropTop * dst.mWidth + src.mCropLeft) * 2;
2312a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
232f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    for (size_t y = 0; y < src.cropHeight(); ++y) {
233f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        for (size_t x = 0; x < src.cropWidth(); x += 2) {
234f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            signed y1 = (signed)src_ptr[2 * x + 1] - 16;
235f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            signed y2 = (signed)src_ptr[2 * x + 3] - 16;
236f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            signed u = (signed)src_ptr[2 * x] - 128;
237f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            signed v = (signed)src_ptr[2 * x + 2] - 128;
2382a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2392a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u_b = u * 517;
2402a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u_g = -u * 100;
2412a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v_g = -v * 208;
2422a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v_r = v * 409;
2432a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2442a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed tmp1 = y1 * 298;
2452a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed b1 = (tmp1 + u_b) / 256;
2462a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed g1 = (tmp1 + v_g + u_g) / 256;
2472a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed r1 = (tmp1 + v_r) / 256;
2482a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2492a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed tmp2 = y2 * 298;
2502a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed b2 = (tmp2 + u_b) / 256;
2512a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed g2 = (tmp2 + v_g + u_g) / 256;
2522a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed r2 = (tmp2 + v_r) / 256;
2532a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2542a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            uint32_t rgb1 =
2552a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                ((kAdjustedClip[r1] >> 3) << 11)
2562a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | ((kAdjustedClip[g1] >> 2) << 5)
2572a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | (kAdjustedClip[b1] >> 3);
2582a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2592a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            uint32_t rgb2 =
2602a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                ((kAdjustedClip[r2] >> 3) << 11)
2612a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | ((kAdjustedClip[g2] >> 2) << 5)
2622a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | (kAdjustedClip[b2] >> 3);
2632a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2644e260ab948787c2a814543077832847deae890fdJames Dong            if (x + 1 < src.cropWidth()) {
2654e260ab948787c2a814543077832847deae890fdJames Dong                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
2664e260ab948787c2a814543077832847deae890fdJames Dong            } else {
2674e260ab948787c2a814543077832847deae890fdJames Dong                dst_ptr[x] = rgb1;
2684e260ab948787c2a814543077832847deae890fdJames Dong            }
2692a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        }
2702a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
271f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        src_ptr += src.mWidth * 2;
2724e260ab948787c2a814543077832847deae890fdJames Dong        dst_ptr += dst.mWidth;
2732a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    }
2741472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber
2751472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    return OK;
2762a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
2772a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
278d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuangstatus_t ColorConverter::convertYUV420PlanarUseLibYUV(
279d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang        const BitmapParams &src, const BitmapParams &dst) {
280026d520295b52d136a6962a05882a696fe620725Chong Zhang    uint8_t *dst_ptr = (uint8_t *)dst.mBits
281026d520295b52d136a6962a05882a696fe620725Chong Zhang        + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
282d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang
283d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang    const uint8_t *src_y =
284026d520295b52d136a6962a05882a696fe620725Chong Zhang        (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft;
285d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang
286d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang    const uint8_t *src_u =
287026d520295b52d136a6962a05882a696fe620725Chong Zhang        (const uint8_t *)src.mBits + src.mStride * src.mHeight
288026d520295b52d136a6962a05882a696fe620725Chong Zhang        + (src.mCropTop / 2) * (src.mStride / 2) + (src.mCropLeft / 2);
289d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang
290d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang    const uint8_t *src_v =
291026d520295b52d136a6962a05882a696fe620725Chong Zhang        src_u + (src.mStride / 2) * (src.mHeight / 2);
292026d520295b52d136a6962a05882a696fe620725Chong Zhang
293026d520295b52d136a6962a05882a696fe620725Chong Zhang    switch (mDstFormat) {
294026d520295b52d136a6962a05882a696fe620725Chong Zhang    case OMX_COLOR_Format16bitRGB565:
295026d520295b52d136a6962a05882a696fe620725Chong Zhang        libyuv::I420ToRGB565(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
296026d520295b52d136a6962a05882a696fe620725Chong Zhang                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
297026d520295b52d136a6962a05882a696fe620725Chong Zhang        break;
298d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang
299026d520295b52d136a6962a05882a696fe620725Chong Zhang    case OMX_COLOR_Format32BitRGBA8888:
300026d520295b52d136a6962a05882a696fe620725Chong Zhang        libyuv::ConvertFromI420(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
301026d520295b52d136a6962a05882a696fe620725Chong Zhang                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight(), libyuv::FOURCC_ABGR);
302026d520295b52d136a6962a05882a696fe620725Chong Zhang        break;
303d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang
304026d520295b52d136a6962a05882a696fe620725Chong Zhang    case OMX_COLOR_Format32bitBGRA8888:
305026d520295b52d136a6962a05882a696fe620725Chong Zhang        libyuv::ConvertFromI420(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
306026d520295b52d136a6962a05882a696fe620725Chong Zhang                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight(), libyuv::FOURCC_ARGB);
307026d520295b52d136a6962a05882a696fe620725Chong Zhang        break;
308026d520295b52d136a6962a05882a696fe620725Chong Zhang
309026d520295b52d136a6962a05882a696fe620725Chong Zhang    default:
310026d520295b52d136a6962a05882a696fe620725Chong Zhang        return ERROR_UNSUPPORTED;
311026d520295b52d136a6962a05882a696fe620725Chong Zhang    }
312d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang
313d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang    return OK;
314d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang}
315d36af484a8dd3bbaf7ed7de31852c9f802243392Hangyu Kuang
3164fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhangstd::function<void (void *, void *, void *, size_t,
3174fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                    signed *, signed *, signed *, signed *)>
3184fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong ZhanggetReadFromSrc(OMX_COLOR_FORMATTYPE srcFormat) {
3194fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    switch(srcFormat) {
3204fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    case OMX_COLOR_FormatYUV420Planar:
3214fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        return [](void *src_y, void *src_u, void *src_v, size_t x,
3224fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                  signed *y1, signed *y2, signed *u, signed *v) {
3234fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            *y1 = ((uint8_t*)src_y)[x] - 16;
3244fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            *y2 = ((uint8_t*)src_y)[x + 1] - 16;
3254fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            *u = ((uint8_t*)src_u)[x / 2] - 128;
3264fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            *v = ((uint8_t*)src_v)[x / 2] - 128;
3274fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        };
3284fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    case OMX_COLOR_FormatYUV420Planar16:
3294fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        return [](void *src_y, void *src_u, void *src_v, size_t x,
3304fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                signed *y1, signed *y2, signed *u, signed *v) {
3314fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            *y1 = (signed)(((uint16_t*)src_y)[x] >> 2) - 16;
3324fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            *y2 = (signed)(((uint16_t*)src_y)[x + 1] >> 2) - 16;
3334fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            *u = (signed)(((uint16_t*)src_u)[x / 2] >> 2) - 128;
3344fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            *v = (signed)(((uint16_t*)src_v)[x / 2] >> 2) - 128;
3354fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        };
3364fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    default:
3374fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        TRESPASS();
3384fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    }
3394fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    return nullptr;
3404fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang}
3414fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang
3424fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhangstd::function<void (void *, bool, signed, signed, signed, signed, signed, signed)>
3434fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong ZhanggetWriteToDst(OMX_COLOR_FORMATTYPE dstFormat, uint8_t *kAdjustedClip) {
3444fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    switch (dstFormat) {
345026d520295b52d136a6962a05882a696fe620725Chong Zhang    case OMX_COLOR_Format16bitRGB565:
346026d520295b52d136a6962a05882a696fe620725Chong Zhang    {
3474fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        return [kAdjustedClip](void *dst_ptr, bool uncropped,
3484fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                               signed r1, signed g1, signed b1,
3494fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                               signed r2, signed g2, signed b2) {
3504fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            uint32_t rgb1 =
3514fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                ((kAdjustedClip[r1] >> 3) << 11)
3524fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                | ((kAdjustedClip[g1] >> 2) << 5)
3534fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                | (kAdjustedClip[b1] >> 3);
354026d520295b52d136a6962a05882a696fe620725Chong Zhang
3554fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            if (uncropped) {
3564fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                uint32_t rgb2 =
3574fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                    ((kAdjustedClip[r2] >> 3) << 11)
3584fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                    | ((kAdjustedClip[g2] >> 2) << 5)
3594fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                    | (kAdjustedClip[b2] >> 3);
360026d520295b52d136a6962a05882a696fe620725Chong Zhang
3614fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                *(uint32_t *)dst_ptr = (rgb2 << 16) | rgb1;
3624fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            } else {
3634fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                *(uint16_t *)dst_ptr = rgb1;
3644fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            }
3654fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        };
366026d520295b52d136a6962a05882a696fe620725Chong Zhang    }
367026d520295b52d136a6962a05882a696fe620725Chong Zhang    case OMX_COLOR_Format32BitRGBA8888:
368026d520295b52d136a6962a05882a696fe620725Chong Zhang    {
3694fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        return [kAdjustedClip](void *dst_ptr, bool uncropped,
3704fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                               signed r1, signed g1, signed b1,
3714fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                               signed r2, signed g2, signed b2) {
3724fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            ((uint32_t *)dst_ptr)[0] =
3734fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                    (kAdjustedClip[r1])
3744fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                    | (kAdjustedClip[g1] << 8)
3754fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                    | (kAdjustedClip[b1] << 16)
376026d520295b52d136a6962a05882a696fe620725Chong Zhang                    | (0xFF << 24);
3774fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang
3784fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            if (uncropped) {
3794fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                ((uint32_t *)dst_ptr)[1] =
3804fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                        (kAdjustedClip[r2])
3814fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                        | (kAdjustedClip[g2] << 8)
3824fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                        | (kAdjustedClip[b2] << 16)
3834fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                        | (0xFF << 24);
3844fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            }
3854fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        };
386026d520295b52d136a6962a05882a696fe620725Chong Zhang    }
387026d520295b52d136a6962a05882a696fe620725Chong Zhang    case OMX_COLOR_Format32bitBGRA8888:
388026d520295b52d136a6962a05882a696fe620725Chong Zhang    {
3894fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        return [kAdjustedClip](void *dst_ptr, bool uncropped,
3904fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                               signed r1, signed g1, signed b1,
3914fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                               signed r2, signed g2, signed b2) {
3924fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            ((uint32_t *)dst_ptr)[0] =
3934fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                    (kAdjustedClip[b1])
3944fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                    | (kAdjustedClip[g1] << 8)
3954fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                    | (kAdjustedClip[r1] << 16)
396026d520295b52d136a6962a05882a696fe620725Chong Zhang                    | (0xFF << 24);
3974fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang
3984fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            if (uncropped) {
3994fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                ((uint32_t *)dst_ptr)[1] =
4004fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                        (kAdjustedClip[b2])
4014fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                        | (kAdjustedClip[g2] << 8)
4024fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                        | (kAdjustedClip[r2] << 16)
4034fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang                        | (0xFF << 24);
4044fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            }
4054fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        };
406026d520295b52d136a6962a05882a696fe620725Chong Zhang    }
407026d520295b52d136a6962a05882a696fe620725Chong Zhang    default:
4084fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        TRESPASS();
409026d520295b52d136a6962a05882a696fe620725Chong Zhang    }
4104fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    return nullptr;
411026d520295b52d136a6962a05882a696fe620725Chong Zhang}
4124fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang
4131472eb39f7516faa26de200d8592464c8aaac38eAndreas Huberstatus_t ColorConverter::convertYUV420Planar(
414f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        const BitmapParams &src, const BitmapParams &dst) {
4151472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    uint8_t *kAdjustedClip = initClip();
416f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
4174fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    auto readFromSrc = getReadFromSrc(mSrcFormat);
4184fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    auto writeToDst = getWriteToDst(mDstFormat, kAdjustedClip);
4194fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang
420026d520295b52d136a6962a05882a696fe620725Chong Zhang    uint8_t *dst_ptr = (uint8_t *)dst.mBits
4214fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
422f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
4234fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    uint8_t *src_y = (uint8_t *)src.mBits
4244fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp;
4252a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4264fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    uint8_t *src_u = (uint8_t *)src.mBits + src.mStride * src.mHeight
4274fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            + (src.mCropTop / 2) * (src.mStride / 2) + src.mCropLeft / 2 * src.mBpp;
4282a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4294fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    uint8_t *src_v = src_u + (src.mStride / 2) * (src.mHeight / 2);
4302a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
431f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    for (size_t y = 0; y < src.cropHeight(); ++y) {
432f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        for (size_t x = 0; x < src.cropWidth(); x += 2) {
4332a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // B = 1.164 * (Y - 16) + 2.018 * (U - 128)
4342a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128)
4352a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // R = 1.164 * (Y - 16) + 1.596 * (V - 128)
4362a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4372a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // B = 298/256 * (Y - 16) + 517/256 * (U - 128)
4382a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128)
4392a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // R = .................. + 409/256 * (V - 128)
4402a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4412a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277
4422a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172
4432a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223
4442a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4452a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534
4462a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432
4472a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481
4482a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4492a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // clip range -278 .. 535
4502a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4514fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            signed y1, y2, u, v;
4524fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            readFromSrc(src_y, src_u, src_v, x, &y1, &y2, &u, &v);
4532a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4542a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u_b = u * 517;
4552a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u_g = -u * 100;
4562a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v_g = -v * 208;
4572a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v_r = v * 409;
4582a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4592a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed tmp1 = y1 * 298;
4602a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed b1 = (tmp1 + u_b) / 256;
4612a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed g1 = (tmp1 + v_g + u_g) / 256;
4622a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed r1 = (tmp1 + v_r) / 256;
4632a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4642a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed tmp2 = y2 * 298;
4652a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed b2 = (tmp2 + u_b) / 256;
4662a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed g2 = (tmp2 + v_g + u_g) / 256;
4672a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed r2 = (tmp2 + v_r) / 256;
4682a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
469026d520295b52d136a6962a05882a696fe620725Chong Zhang            bool uncropped = x + 1 < src.cropWidth();
4704fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang            writeToDst(dst_ptr + x * dst.mBpp, uncropped, r1, g1, b1, r2, g2, b2);
4712a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        }
4722a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
473026d520295b52d136a6962a05882a696fe620725Chong Zhang        src_y += src.mStride;
4742a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4752a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        if (y & 1) {
476026d520295b52d136a6962a05882a696fe620725Chong Zhang            src_u += src.mStride / 2;
477026d520295b52d136a6962a05882a696fe620725Chong Zhang            src_v += src.mStride / 2;
4782a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        }
4792a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
480026d520295b52d136a6962a05882a696fe620725Chong Zhang        dst_ptr += dst.mStride;
4812a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    }
4821472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber
4831472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    return OK;
4842a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
4852a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4864fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhangstatus_t ColorConverter::convertYUV420Planar16(
4874fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        const BitmapParams &src, const BitmapParams &dst) {
4884fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    if (mDstFormat == OMX_COLOR_FormatYUV444Y410) {
4894fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang        return convertYUV420Planar16ToY410(src, dst);
4904fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    }
4914fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang
4924fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang    return convertYUV420Planar(src, dst);
4934fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang}
4944fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhang
4952d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang/*
4962d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang * Pack 10-bit YUV into RGBA_1010102.
4972d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *
4982d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang * Media sends 10-bit YUV in a RGBA_1010102 format buffer. SF will handle
4992d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang * the conversion to RGB using RenderEngine fallback.
5002d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *
5012d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang * We do not perform a YUV->RGB conversion here, however the conversion with
5022d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang * BT2020 to Full range is below for reference:
5032d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *
5042d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *   B = 1.168  *(Y - 64) + 2.148  *(U - 512)
5052d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *   G = 1.168  *(Y - 64) - 0.652  *(V - 512) - 0.188  *(U - 512)
5062d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *   R = 1.168  *(Y - 64) + 1.683  *(V - 512)
5072d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *
5082d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *   B = 1196/1024  *(Y - 64) + 2200/1024  *(U - 512)
5092d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *   G = .................... -  668/1024  *(V - 512) - 192/1024  *(U - 512)
5102d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *   R = .................... + 1723/1024  *(V - 512)
5112d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *
5122d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *   min_B = (1196  *(- 64) + 2200  *(- 512)) / 1024 = -1175
5132d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *   min_G = (1196  *(- 64) - 668  *(1023 - 512) - 192  *(1023 - 512)) / 1024 = -504
5142d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *   min_R = (1196  *(- 64) + 1723  *(- 512)) / 1024 = -937
5152d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *
5162d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *   max_B = (1196  *(1023 - 64) + 2200  *(1023 - 512)) / 1024 = 2218
5172d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *   max_G = (1196  *(1023 - 64) - 668  *(- 512) - 192  *(- 512)) / 1024 = 1551
5182d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *   max_R = (1196  *(1023 - 64) + 1723  *(1023 - 512)) / 1024 = 1980
5192d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *
5202d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *   clip range -1175 .. 2218
5212d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang *
5222d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang */
5232d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5242d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#if !USE_NEON_Y410
5252d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5264fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhangstatus_t ColorConverter::convertYUV420Planar16ToY410(
5272d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        const BitmapParams &src, const BitmapParams &dst) {
5282d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    uint8_t *dst_ptr = (uint8_t *)dst.mBits
5292d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
5302d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5312d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    const uint8_t *src_y =
5322d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp;
5332d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5342d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    const uint8_t *src_u =
5352d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        (const uint8_t *)src.mBits + src.mStride * src.mHeight
5362d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        + (src.mCropTop / 2) * (src.mStride / 2) + (src.mCropLeft / 2) * src.mBpp;
5372d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5382d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    const uint8_t *src_v =
5392d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        src_u + (src.mStride / 2) * (src.mHeight / 2);
5402d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5412d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    // Converting two lines at a time, slightly faster
5422d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    for (size_t y = 0; y < src.cropHeight(); y += 2) {
5432d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        uint32_t *dst_top = (uint32_t *) dst_ptr;
5442d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        uint32_t *dst_bot = (uint32_t *) (dst_ptr + dst.mStride);
5452d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        uint16_t *ptr_ytop = (uint16_t*) src_y;
5462d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        uint16_t *ptr_ybot = (uint16_t*) (src_y + src.mStride);
5472d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        uint16_t *ptr_u = (uint16_t*) src_u;
5482d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        uint16_t *ptr_v = (uint16_t*) src_v;
5492d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5502d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
5512d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        size_t x = 0;
5522d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        for (; x < src.cropWidth() - 3; x += 4) {
5532d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            u01 = *((uint32_t*)ptr_u); ptr_u += 2;
5542d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            v01 = *((uint32_t*)ptr_v); ptr_v += 2;
5552d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5562d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            y01 = *((uint32_t*)ptr_ytop); ptr_ytop += 2;
5572d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            y23 = *((uint32_t*)ptr_ytop); ptr_ytop += 2;
5582d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            y45 = *((uint32_t*)ptr_ybot); ptr_ybot += 2;
5592d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            y67 = *((uint32_t*)ptr_ybot); ptr_ybot += 2;
5602d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5612d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
5622d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
5632d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5642d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            *dst_top++ = ((y01 & 0x3FF) << 10) | uv0;
5652d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            *dst_top++ = ((y01 >> 16) << 10) | uv0;
5662d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            *dst_top++ = ((y23 & 0x3FF) << 10) | uv1;
5672d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            *dst_top++ = ((y23 >> 16) << 10) | uv1;
5682d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5692d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            *dst_bot++ = ((y45 & 0x3FF) << 10) | uv0;
5702d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            *dst_bot++ = ((y45 >> 16) << 10) | uv0;
5712d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            *dst_bot++ = ((y67 & 0x3FF) << 10) | uv1;
5722d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            *dst_bot++ = ((y67 >> 16) << 10) | uv1;
5732d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        }
5742d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5752d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        // There should be at most 2 more pixels to process. Note that we don't
5762d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        // need to consider odd case as the buffer is always aligned to even.
5772d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        if (x < src.cropWidth()) {
5782d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            u01 = *ptr_u;
5792d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            v01 = *ptr_v;
5802d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            y01 = *((uint32_t*)ptr_ytop);
5812d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            y45 = *((uint32_t*)ptr_ybot);
5822d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
5832d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            *dst_top++ = ((y01 & 0x3FF) << 10) | uv0;
5842d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            *dst_top++ = ((y01 >> 16) << 10) | uv0;
5852d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            *dst_bot++ = ((y45 & 0x3FF) << 10) | uv0;
5862d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            *dst_bot++ = ((y45 >> 16) << 10) | uv0;
5872d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        }
5882d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5892d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        src_y += src.mStride * 2;
5902d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        src_u += src.mStride / 2;
5912d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        src_v += src.mStride / 2;
5922d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        dst_ptr += dst.mStride * 2;
5932d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    }
5942d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5952d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    return OK;
5962d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang}
5972d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
5982d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#else
5992d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6004fdc4ce9d1a9d94801faf904ebf4f11e009fdec7Chong Zhangstatus_t ColorConverter::convertYUV420Planar16ToY410(
6012d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        const BitmapParams &src, const BitmapParams &dst) {
6022d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    uint8_t *out = (uint8_t *)dst.mBits
6032d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
6042d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6052d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    const uint8_t *src_y =
6062d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp;
6072d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6082d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    const uint8_t *src_u =
6092d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        (const uint8_t *)src.mBits + src.mStride * src.mHeight
6102d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        + (src.mCropTop / 2) * (src.mStride / 2) + (src.mCropLeft / 2) * src.mBpp;
6112d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6122d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    const uint8_t *src_v =
6132d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        src_u + (src.mStride / 2) * (src.mHeight / 2);
6142d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6152d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    for (size_t y = 0; y < src.cropHeight(); y++) {
6162d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        uint16_t *ptr_y = (uint16_t*) src_y;
6172d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        uint16_t *ptr_u = (uint16_t*) src_u;
6182d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        uint16_t *ptr_v = (uint16_t*) src_v;
6192d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        uint32_t *ptr_out = (uint32_t *) out;
6202d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6212d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        // Process 16-pixel at a time.
6222d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        uint32_t *ptr_limit = ptr_out + (src.cropWidth() & ~15);
6232d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        while (ptr_out < ptr_limit) {
6242d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint16x4_t u0123 = vld1_u16(ptr_u); ptr_u += 4;
6252d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint16x4_t u4567 = vld1_u16(ptr_u); ptr_u += 4;
6262d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint16x4_t v0123 = vld1_u16(ptr_v); ptr_v += 4;
6272d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint16x4_t v4567 = vld1_u16(ptr_v); ptr_v += 4;
6282d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint16x4_t y0123 = vld1_u16(ptr_y); ptr_y += 4;
6292d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint16x4_t y4567 = vld1_u16(ptr_y); ptr_y += 4;
6302d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint16x4_t y89ab = vld1_u16(ptr_y); ptr_y += 4;
6312d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint16x4_t ycdef = vld1_u16(ptr_y); ptr_y += 4;
6322d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6332d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint32x2_t uvtempl;
6342d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint32x4_t uvtempq;
6352d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6362d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uvtempq = vaddw_u16(vshll_n_u16(v0123, 20), u0123);
6372d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6382d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uvtempl = vget_low_u32(uvtempq);
6392d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint32x4_t uv0011 = vreinterpretq_u32_u64(
6402d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang                    vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl));
6412d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6422d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uvtempl = vget_high_u32(uvtempq);
6432d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint32x4_t uv2233 = vreinterpretq_u32_u64(
6442d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang                    vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl));
6452d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6462d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uvtempq = vaddw_u16(vshll_n_u16(v4567, 20), u4567);
6472d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6482d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uvtempl = vget_low_u32(uvtempq);
6492d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint32x4_t uv4455 = vreinterpretq_u32_u64(
6502d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang                    vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl));
6512d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6522d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uvtempl = vget_high_u32(uvtempq);
6532d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint32x4_t uv6677 = vreinterpretq_u32_u64(
6542d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang                    vaddw_u32(vshll_n_u32(uvtempl, 32), uvtempl));
6552d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6562d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint32x4_t dsttemp;
6572d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6582d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            dsttemp = vorrq_u32(uv0011, vshll_n_u16(y0123, 10));
6592d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            vst1q_u32(ptr_out, dsttemp); ptr_out += 4;
6602d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6612d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            dsttemp = vorrq_u32(uv2233, vshll_n_u16(y4567, 10));
6622d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            vst1q_u32(ptr_out, dsttemp); ptr_out += 4;
6632d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6642d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            dsttemp = vorrq_u32(uv4455, vshll_n_u16(y89ab, 10));
6652d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            vst1q_u32(ptr_out, dsttemp); ptr_out += 4;
6662d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6672d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            dsttemp = vorrq_u32(uv6677, vshll_n_u16(ycdef, 10));
6682d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            vst1q_u32(ptr_out, dsttemp); ptr_out += 4;
6692d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        }
6702d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6712d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        src_y += src.mStride;
6722d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        if (y & 1) {
6732d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            src_u += src.mStride / 2;
6742d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            src_v += src.mStride / 2;
6752d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        }
6762d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        out += dst.mStride;
6772d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    }
6782d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6792d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    // Process the left-overs out-of-loop, 2-pixel at a time. Note that we don't
6802d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    // need to consider odd case as the buffer is always aligned to even.
6812d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    if (src.cropWidth() & 15) {
6822d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        size_t xstart = (src.cropWidth() & ~15);
6832d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6842d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        uint8_t *out = (uint8_t *)dst.mBits + dst.mCropTop * dst.mStride
6852d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang                + (dst.mCropLeft + xstart) * dst.mBpp;
6862d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6872d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        const uint8_t *src_y = (const uint8_t *)src.mBits + src.mCropTop * src.mStride
6882d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang                + (src.mCropLeft + xstart) * src.mBpp;
6892d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6902d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        const uint8_t *src_u = (const uint8_t *)src.mBits + src.mStride * src.mHeight
6912d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            + (src.mCropTop / 2) * (src.mStride / 2)
6922d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            + ((src.mCropLeft + xstart) / 2) * src.mBpp;
6932d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6942d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        const uint8_t *src_v = src_u + (src.mStride / 2) * (src.mHeight / 2);
6952d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
6962d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        for (size_t y = 0; y < src.cropHeight(); y++) {
6972d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint16_t *ptr_y = (uint16_t*) src_y;
6982d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint16_t *ptr_u = (uint16_t*) src_u;
6992d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint16_t *ptr_v = (uint16_t*) src_v;
7002d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            uint32_t *ptr_out = (uint32_t *) out;
7012d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            for (size_t x = xstart; x < src.cropWidth(); x += 2) {
7022d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang                uint16_t u = *ptr_u++;
7032d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang                uint16_t v = *ptr_v++;
7042d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang                uint32_t y01 = *((uint32_t*)ptr_y); ptr_y += 2;
7052d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang                uint32_t uv = u | (((uint32_t)v) << 20);
7062d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang                *ptr_out++ = ((y01 & 0x3FF) << 10) | uv;
7072d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang                *ptr_out++ = ((y01 >> 16) << 10) | uv;
7082d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            }
7092d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            src_y += src.mStride;
7102d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            if (y & 1) {
7112d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang                src_u += src.mStride / 2;
7122d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang                src_v += src.mStride / 2;
7132d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            }
7142d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            out += dst.mStride;
7152d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        }
7162d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    }
7172d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
7182d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    return OK;
7192d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang}
7202d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
7212d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang#endif // USE_NEON_Y410
7222d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
7231472eb39f7516faa26de200d8592464c8aaac38eAndreas Huberstatus_t ColorConverter::convertQCOMYUV420SemiPlanar(
724f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        const BitmapParams &src, const BitmapParams &dst) {
7252a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    uint8_t *kAdjustedClip = initClip();
7262a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
7274e260ab948787c2a814543077832847deae890fdJames Dong    uint16_t *dst_ptr = (uint16_t *)dst.mBits
7284e260ab948787c2a814543077832847deae890fdJames Dong        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
729f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
730f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    const uint8_t *src_y =
731f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
7322a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
7332a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    const uint8_t *src_u =
734f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        (const uint8_t *)src_y + src.mWidth * src.mHeight
735f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        + src.mCropTop * src.mWidth + src.mCropLeft;
7362a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
737f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    for (size_t y = 0; y < src.cropHeight(); ++y) {
738f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        for (size_t x = 0; x < src.cropWidth(); x += 2) {
7392a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed y1 = (signed)src_y[x] - 16;
7402a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed y2 = (signed)src_y[x + 1] - 16;
7412a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
7422a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u = (signed)src_u[x & ~1] - 128;
7432a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v = (signed)src_u[(x & ~1) + 1] - 128;
7442a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
7452a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u_b = u * 517;
7462a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u_g = -u * 100;
7472a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v_g = -v * 208;
7482a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v_r = v * 409;
7492a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
7502a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed tmp1 = y1 * 298;
7512a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed b1 = (tmp1 + u_b) / 256;
7522a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed g1 = (tmp1 + v_g + u_g) / 256;
7532a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed r1 = (tmp1 + v_r) / 256;
7542a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
7552a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed tmp2 = y2 * 298;
7562a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed b2 = (tmp2 + u_b) / 256;
7572a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed g2 = (tmp2 + v_g + u_g) / 256;
7581c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed r2 = (tmp2 + v_r) / 256;
7591c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
7601c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            uint32_t rgb1 =
7611c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber                ((kAdjustedClip[b1] >> 3) << 11)
7621c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber                | ((kAdjustedClip[g1] >> 2) << 5)
7631c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber                | (kAdjustedClip[r1] >> 3);
7641c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
7651c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            uint32_t rgb2 =
7661c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber                ((kAdjustedClip[b2] >> 3) << 11)
7671c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber                | ((kAdjustedClip[g2] >> 2) << 5)
7681c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber                | (kAdjustedClip[r2] >> 3);
7691c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
7704e260ab948787c2a814543077832847deae890fdJames Dong            if (x + 1 < src.cropWidth()) {
7714e260ab948787c2a814543077832847deae890fdJames Dong                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
7724e260ab948787c2a814543077832847deae890fdJames Dong            } else {
7734e260ab948787c2a814543077832847deae890fdJames Dong                dst_ptr[x] = rgb1;
7744e260ab948787c2a814543077832847deae890fdJames Dong            }
7751c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber        }
7761c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
777f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        src_y += src.mWidth;
7781c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
7791c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber        if (y & 1) {
780f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            src_u += src.mWidth;
7811c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber        }
7821c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
7834e260ab948787c2a814543077832847deae890fdJames Dong        dst_ptr += dst.mWidth;
7841c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber    }
7851472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber
7861472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    return OK;
7871c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber}
7881c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
7891472eb39f7516faa26de200d8592464c8aaac38eAndreas Huberstatus_t ColorConverter::convertYUV420SemiPlanar(
790f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        const BitmapParams &src, const BitmapParams &dst) {
791f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    // XXX Untested
7921c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
7931c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber    uint8_t *kAdjustedClip = initClip();
7941c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
7954e260ab948787c2a814543077832847deae890fdJames Dong    uint16_t *dst_ptr = (uint16_t *)dst.mBits
7964e260ab948787c2a814543077832847deae890fdJames Dong        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
797f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
798f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    const uint8_t *src_y =
799f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
8001c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
8011c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber    const uint8_t *src_u =
802f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        (const uint8_t *)src_y + src.mWidth * src.mHeight
803f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        + src.mCropTop * src.mWidth + src.mCropLeft;
8041c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
805f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    for (size_t y = 0; y < src.cropHeight(); ++y) {
806f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        for (size_t x = 0; x < src.cropWidth(); x += 2) {
8071c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed y1 = (signed)src_y[x] - 16;
8081c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed y2 = (signed)src_y[x + 1] - 16;
8091c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
8101c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed v = (signed)src_u[x & ~1] - 128;
8111c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed u = (signed)src_u[(x & ~1) + 1] - 128;
8121c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
8131c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed u_b = u * 517;
8141c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed u_g = -u * 100;
8151c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed v_g = -v * 208;
8161c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed v_r = v * 409;
8171c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
8181c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed tmp1 = y1 * 298;
8191c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed b1 = (tmp1 + u_b) / 256;
8201c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed g1 = (tmp1 + v_g + u_g) / 256;
8211c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed r1 = (tmp1 + v_r) / 256;
8221c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
8231c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed tmp2 = y2 * 298;
8241c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed b2 = (tmp2 + u_b) / 256;
8251c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed g2 = (tmp2 + v_g + u_g) / 256;
8262a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed r2 = (tmp2 + v_r) / 256;
8272a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
8282a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            uint32_t rgb1 =
8292a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                ((kAdjustedClip[b1] >> 3) << 11)
8302a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | ((kAdjustedClip[g1] >> 2) << 5)
8312a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | (kAdjustedClip[r1] >> 3);
8322a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
8332a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            uint32_t rgb2 =
8342a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                ((kAdjustedClip[b2] >> 3) << 11)
8352a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | ((kAdjustedClip[g2] >> 2) << 5)
8362a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | (kAdjustedClip[r2] >> 3);
8372a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
8384e260ab948787c2a814543077832847deae890fdJames Dong            if (x + 1 < src.cropWidth()) {
8394e260ab948787c2a814543077832847deae890fdJames Dong                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
8404e260ab948787c2a814543077832847deae890fdJames Dong            } else {
8414e260ab948787c2a814543077832847deae890fdJames Dong                dst_ptr[x] = rgb1;
8424e260ab948787c2a814543077832847deae890fdJames Dong            }
8432a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        }
8442a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
845f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        src_y += src.mWidth;
8462a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
8472a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        if (y & 1) {
848f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            src_u += src.mWidth;
8492a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        }
8502a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
8514e260ab948787c2a814543077832847deae890fdJames Dong        dst_ptr += dst.mWidth;
8522a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    }
8531472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber
8541472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    return OK;
8552a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
8562a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
857cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajanstatus_t ColorConverter::convertTIYUV420PackedSemiPlanar(
858cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan        const BitmapParams &src, const BitmapParams &dst) {
8593571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber    uint8_t *kAdjustedClip = initClip();
860cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
8614e260ab948787c2a814543077832847deae890fdJames Dong    uint16_t *dst_ptr = (uint16_t *)dst.mBits
8624e260ab948787c2a814543077832847deae890fdJames Dong        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
863cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
864e14a36f37035c2655df13838c15fdb61e76c3e65Angela Stegmaier    const uint8_t *src_y =
865e14a36f37035c2655df13838c15fdb61e76c3e65Angela Stegmaier        (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
866cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
8673571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber    const uint8_t *src_u =
8683571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber        (const uint8_t *)src_y + src.mWidth * (src.mHeight - src.mCropTop / 2);
869cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
8703571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber    for (size_t y = 0; y < src.cropHeight(); ++y) {
8713571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber        for (size_t x = 0; x < src.cropWidth(); x += 2) {
8723571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber            signed y1 = (signed)src_y[x] - 16;
8733571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber            signed y2 = (signed)src_y[x + 1] - 16;
874cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
8753571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber            signed u = (signed)src_u[x & ~1] - 128;
8763571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber            signed v = (signed)src_u[(x & ~1) + 1] - 128;
877cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
878cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed u_b = u * 517;
879cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed u_g = -u * 100;
880cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed v_g = -v * 208;
881cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed v_r = v * 409;
882cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
883cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed tmp1 = y1 * 298;
884cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed b1 = (tmp1 + u_b) / 256;
885cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed g1 = (tmp1 + v_g + u_g) / 256;
886cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed r1 = (tmp1 + v_r) / 256;
887cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
888cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed tmp2 = y2 * 298;
889cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed b2 = (tmp2 + u_b) / 256;
890cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed g2 = (tmp2 + v_g + u_g) / 256;
891cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed r2 = (tmp2 + v_r) / 256;
892cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
893cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            uint32_t rgb1 =
894cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan                ((kAdjustedClip[r1] >> 3) << 11)
895cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan                | ((kAdjustedClip[g1] >> 2) << 5)
896cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan                | (kAdjustedClip[b1] >> 3);
897cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
898cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            uint32_t rgb2 =
899cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan                ((kAdjustedClip[r2] >> 3) << 11)
9003571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber                | ((kAdjustedClip[g2] >> 2) << 5)
9013571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber                | (kAdjustedClip[b2] >> 3);
902cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
9034e260ab948787c2a814543077832847deae890fdJames Dong            if (x + 1 < src.cropWidth()) {
9044e260ab948787c2a814543077832847deae890fdJames Dong                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
9054e260ab948787c2a814543077832847deae890fdJames Dong            } else {
9064e260ab948787c2a814543077832847deae890fdJames Dong                dst_ptr[x] = rgb1;
9074e260ab948787c2a814543077832847deae890fdJames Dong            }
908cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan        }
909cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
9103571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber        src_y += src.mWidth;
9113571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber
9123571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber        if (y & 1) {
9133571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber            src_u += src.mWidth;
914cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan        }
915cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
9164e260ab948787c2a814543077832847deae890fdJames Dong        dst_ptr += dst.mWidth;
917cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan    }
9183571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber
919cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan    return OK;
920cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan}
921cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
9222a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huberuint8_t *ColorConverter::initClip() {
9232a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    static const signed kClipMin = -278;
9242a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    static const signed kClipMax = 535;
9252a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
9262a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    if (mClip == NULL) {
9272a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        mClip = new uint8_t[kClipMax - kClipMin + 1];
9282a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
9292a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        for (signed i = kClipMin; i <= kClipMax; ++i) {
9302a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
9312a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        }
9322a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    }
9332a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
9342a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    return &mClip[-kClipMin];
9352a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
9362a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
9372a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}  // namespace android
938