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>
222a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber#include <media/stagefright/ColorConverter.h>
231472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber#include <media/stagefright/MediaErrors.h>
242a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
252a4a7d5af053a17586a262a1267ba993e31790f1Andreas Hubernamespace android {
262a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
272a4a7d5af053a17586a262a1267ba993e31790f1Andreas HuberColorConverter::ColorConverter(
282a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to)
292a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    : mSrcFormat(from),
302a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber      mDstFormat(to),
312a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber      mClip(NULL) {
322a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
332a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
342a4a7d5af053a17586a262a1267ba993e31790f1Andreas HuberColorConverter::~ColorConverter() {
352a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    delete[] mClip;
362a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    mClip = NULL;
372a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
382a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
392a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huberbool ColorConverter::isValid() const {
402a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    if (mDstFormat != OMX_COLOR_Format16bitRGB565) {
412a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        return false;
422a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    }
432a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
442a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    switch (mSrcFormat) {
452a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        case OMX_COLOR_FormatYUV420Planar:
462a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        case OMX_COLOR_FormatCbYCrY:
472a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
481c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber        case OMX_COLOR_FormatYUV420SemiPlanar:
49cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan        case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
502a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            return true;
512a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
522a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        default:
532a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            return false;
542a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    }
552a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
562a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
57f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas HuberColorConverter::BitmapParams::BitmapParams(
58f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        void *bits,
592a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        size_t width, size_t height,
60f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t cropLeft, size_t cropTop,
61f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t cropRight, size_t cropBottom)
62f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    : mBits(bits),
63f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber      mWidth(width),
64f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber      mHeight(height),
65f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber      mCropLeft(cropLeft),
66f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber      mCropTop(cropTop),
67f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber      mCropRight(cropRight),
68f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber      mCropBottom(cropBottom) {
69f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber}
70f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
71f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Hubersize_t ColorConverter::BitmapParams::cropWidth() const {
72f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    return mCropRight - mCropLeft + 1;
73f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber}
74f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
75f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Hubersize_t ColorConverter::BitmapParams::cropHeight() const {
76f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    return mCropBottom - mCropTop + 1;
77f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber}
78f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
791472eb39f7516faa26de200d8592464c8aaac38eAndreas Huberstatus_t ColorConverter::convert(
80f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        const void *srcBits,
81f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t srcWidth, size_t srcHeight,
82f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t srcCropLeft, size_t srcCropTop,
83f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t srcCropRight, size_t srcCropBottom,
84f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        void *dstBits,
85f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t dstWidth, size_t dstHeight,
86f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t dstCropLeft, size_t dstCropTop,
87f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        size_t dstCropRight, size_t dstCropBottom) {
881472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    if (mDstFormat != OMX_COLOR_Format16bitRGB565) {
891472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber        return ERROR_UNSUPPORTED;
901472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    }
912a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
92f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    BitmapParams src(
93f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            const_cast<void *>(srcBits),
94f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            srcWidth, srcHeight,
95f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            srcCropLeft, srcCropTop, srcCropRight, srcCropBottom);
96f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
97f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    BitmapParams dst(
98f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            dstBits,
99f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            dstWidth, dstHeight,
100f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            dstCropLeft, dstCropTop, dstCropRight, dstCropBottom);
101f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
1021472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    status_t err;
1031472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber
1042a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    switch (mSrcFormat) {
1052a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        case OMX_COLOR_FormatYUV420Planar:
1061472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber            err = convertYUV420Planar(src, dst);
1072a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            break;
1082a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1092a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        case OMX_COLOR_FormatCbYCrY:
1101472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber            err = convertCbYCrY(src, dst);
1112a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            break;
1122a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1132a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
1141472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber            err = convertQCOMYUV420SemiPlanar(src, dst);
1152a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            break;
1162a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1171c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber        case OMX_COLOR_FormatYUV420SemiPlanar:
1181472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber            err = convertYUV420SemiPlanar(src, dst);
1191c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            break;
1201c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
121cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan        case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
122cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            err = convertTIYUV420PackedSemiPlanar(src, dst);
123cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            break;
124cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
1252a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        default:
1262a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        {
1272a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            CHECK(!"Should not be here. Unknown color conversion.");
1282a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            break;
1292a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        }
1302a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    }
1311472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber
1321472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    return err;
1332a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
1342a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1351472eb39f7516faa26de200d8592464c8aaac38eAndreas Huberstatus_t ColorConverter::convertCbYCrY(
136f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        const BitmapParams &src, const BitmapParams &dst) {
137f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    // XXX Untested
1382a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1392a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    uint8_t *kAdjustedClip = initClip();
1402a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1411472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    if (!((src.mCropLeft & 1) == 0
1421472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber        && src.cropWidth() == dst.cropWidth()
1431472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber        && src.cropHeight() == dst.cropHeight())) {
1441472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber        return ERROR_UNSUPPORTED;
1451472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    }
146f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
1474e260ab948787c2a814543077832847deae890fdJames Dong    uint16_t *dst_ptr = (uint16_t *)dst.mBits
1484e260ab948787c2a814543077832847deae890fdJames Dong        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
1492a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
150f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    const uint8_t *src_ptr = (const uint8_t *)src.mBits
151f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        + (src.mCropTop * dst.mWidth + src.mCropLeft) * 2;
1522a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
153f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    for (size_t y = 0; y < src.cropHeight(); ++y) {
154f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        for (size_t x = 0; x < src.cropWidth(); x += 2) {
155f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            signed y1 = (signed)src_ptr[2 * x + 1] - 16;
156f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            signed y2 = (signed)src_ptr[2 * x + 3] - 16;
157f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            signed u = (signed)src_ptr[2 * x] - 128;
158f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            signed v = (signed)src_ptr[2 * x + 2] - 128;
1592a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1602a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u_b = u * 517;
1612a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u_g = -u * 100;
1622a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v_g = -v * 208;
1632a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v_r = v * 409;
1642a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1652a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed tmp1 = y1 * 298;
1662a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed b1 = (tmp1 + u_b) / 256;
1672a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed g1 = (tmp1 + v_g + u_g) / 256;
1682a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed r1 = (tmp1 + v_r) / 256;
1692a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1702a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed tmp2 = y2 * 298;
1712a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed b2 = (tmp2 + u_b) / 256;
1722a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed g2 = (tmp2 + v_g + u_g) / 256;
1732a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed r2 = (tmp2 + v_r) / 256;
1742a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1752a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            uint32_t rgb1 =
1762a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                ((kAdjustedClip[r1] >> 3) << 11)
1772a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | ((kAdjustedClip[g1] >> 2) << 5)
1782a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | (kAdjustedClip[b1] >> 3);
1792a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1802a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            uint32_t rgb2 =
1812a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                ((kAdjustedClip[r2] >> 3) << 11)
1822a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | ((kAdjustedClip[g2] >> 2) << 5)
1832a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | (kAdjustedClip[b2] >> 3);
1842a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1854e260ab948787c2a814543077832847deae890fdJames Dong            if (x + 1 < src.cropWidth()) {
1864e260ab948787c2a814543077832847deae890fdJames Dong                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
1874e260ab948787c2a814543077832847deae890fdJames Dong            } else {
1884e260ab948787c2a814543077832847deae890fdJames Dong                dst_ptr[x] = rgb1;
1894e260ab948787c2a814543077832847deae890fdJames Dong            }
1902a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        }
1912a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
192f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        src_ptr += src.mWidth * 2;
1934e260ab948787c2a814543077832847deae890fdJames Dong        dst_ptr += dst.mWidth;
1942a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    }
1951472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber
1961472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    return OK;
1972a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
1982a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
1991472eb39f7516faa26de200d8592464c8aaac38eAndreas Huberstatus_t ColorConverter::convertYUV420Planar(
200f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        const BitmapParams &src, const BitmapParams &dst) {
201d7be5c5e812ad79d4838737a5e4dd81a8d776a0dAndreas Huber    if (!((src.mCropLeft & 1) == 0
2021472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber            && src.cropWidth() == dst.cropWidth()
2031472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber            && src.cropHeight() == dst.cropHeight())) {
2041472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber        return ERROR_UNSUPPORTED;
2051472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    }
2062a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2071472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    uint8_t *kAdjustedClip = initClip();
208f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
209d7be5c5e812ad79d4838737a5e4dd81a8d776a0dAndreas Huber    uint16_t *dst_ptr = (uint16_t *)dst.mBits
210d7be5c5e812ad79d4838737a5e4dd81a8d776a0dAndreas Huber        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
211f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
212f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    const uint8_t *src_y =
213f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
2142a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2152a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    const uint8_t *src_u =
216f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        (const uint8_t *)src_y + src.mWidth * src.mHeight
217f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        + src.mCropTop * (src.mWidth / 2) + src.mCropLeft / 2;
2182a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2192a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    const uint8_t *src_v =
220f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        src_u + (src.mWidth / 2) * (src.mHeight / 2);
2212a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
222f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    for (size_t y = 0; y < src.cropHeight(); ++y) {
223f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        for (size_t x = 0; x < src.cropWidth(); x += 2) {
2242a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // B = 1.164 * (Y - 16) + 2.018 * (U - 128)
2252a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128)
2262a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // R = 1.164 * (Y - 16) + 1.596 * (V - 128)
2272a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2282a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // B = 298/256 * (Y - 16) + 517/256 * (U - 128)
2292a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128)
2302a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // R = .................. + 409/256 * (V - 128)
2312a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2322a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277
2332a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172
2342a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223
2352a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2362a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534
2372a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432
2382a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481
2392a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2402a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            // clip range -278 .. 535
2412a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2422a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed y1 = (signed)src_y[x] - 16;
2432a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed y2 = (signed)src_y[x + 1] - 16;
2442a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2452a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u = (signed)src_u[x / 2] - 128;
2462a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v = (signed)src_v[x / 2] - 128;
2472a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2482a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u_b = u * 517;
2492a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u_g = -u * 100;
2502a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v_g = -v * 208;
2512a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v_r = v * 409;
2522a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2532a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed tmp1 = y1 * 298;
2542a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed b1 = (tmp1 + u_b) / 256;
2552a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed g1 = (tmp1 + v_g + u_g) / 256;
2562a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed r1 = (tmp1 + v_r) / 256;
2572a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2582a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed tmp2 = y2 * 298;
2592a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed b2 = (tmp2 + u_b) / 256;
2602a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed g2 = (tmp2 + v_g + u_g) / 256;
2612a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed r2 = (tmp2 + v_r) / 256;
2622a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2632a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            uint32_t rgb1 =
2642a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                ((kAdjustedClip[r1] >> 3) << 11)
2652a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | ((kAdjustedClip[g1] >> 2) << 5)
2662a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | (kAdjustedClip[b1] >> 3);
2672a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2682a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            uint32_t rgb2 =
2692a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                ((kAdjustedClip[r2] >> 3) << 11)
2702a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | ((kAdjustedClip[g2] >> 2) << 5)
2712a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | (kAdjustedClip[b2] >> 3);
2722a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
273d7be5c5e812ad79d4838737a5e4dd81a8d776a0dAndreas Huber            if (x + 1 < src.cropWidth()) {
274d7be5c5e812ad79d4838737a5e4dd81a8d776a0dAndreas Huber                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
275d7be5c5e812ad79d4838737a5e4dd81a8d776a0dAndreas Huber            } else {
276d7be5c5e812ad79d4838737a5e4dd81a8d776a0dAndreas Huber                dst_ptr[x] = rgb1;
277d7be5c5e812ad79d4838737a5e4dd81a8d776a0dAndreas Huber            }
2782a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        }
2792a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
280f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        src_y += src.mWidth;
2812a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2822a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        if (y & 1) {
283f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            src_u += src.mWidth / 2;
284f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            src_v += src.mWidth / 2;
2852a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        }
2862a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
287d7be5c5e812ad79d4838737a5e4dd81a8d776a0dAndreas Huber        dst_ptr += dst.mWidth;
2882a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    }
2891472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber
2901472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    return OK;
2912a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
2922a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2931472eb39f7516faa26de200d8592464c8aaac38eAndreas Huberstatus_t ColorConverter::convertQCOMYUV420SemiPlanar(
294f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        const BitmapParams &src, const BitmapParams &dst) {
2952a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    uint8_t *kAdjustedClip = initClip();
2962a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
2974e260ab948787c2a814543077832847deae890fdJames Dong    if (!((src.mCropLeft & 1) == 0
2981472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber            && src.cropWidth() == dst.cropWidth()
2991472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber            && src.cropHeight() == dst.cropHeight())) {
3001472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber        return ERROR_UNSUPPORTED;
3011472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    }
302f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
3034e260ab948787c2a814543077832847deae890fdJames Dong    uint16_t *dst_ptr = (uint16_t *)dst.mBits
3044e260ab948787c2a814543077832847deae890fdJames Dong        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
305f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
306f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    const uint8_t *src_y =
307f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
3082a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
3092a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    const uint8_t *src_u =
310f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        (const uint8_t *)src_y + src.mWidth * src.mHeight
311f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        + src.mCropTop * src.mWidth + src.mCropLeft;
3122a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
313f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    for (size_t y = 0; y < src.cropHeight(); ++y) {
314f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        for (size_t x = 0; x < src.cropWidth(); x += 2) {
3152a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed y1 = (signed)src_y[x] - 16;
3162a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed y2 = (signed)src_y[x + 1] - 16;
3172a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
3182a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u = (signed)src_u[x & ~1] - 128;
3192a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v = (signed)src_u[(x & ~1) + 1] - 128;
3202a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
3212a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u_b = u * 517;
3222a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed u_g = -u * 100;
3232a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v_g = -v * 208;
3242a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed v_r = v * 409;
3252a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
3262a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed tmp1 = y1 * 298;
3272a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed b1 = (tmp1 + u_b) / 256;
3282a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed g1 = (tmp1 + v_g + u_g) / 256;
3292a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed r1 = (tmp1 + v_r) / 256;
3302a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
3312a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed tmp2 = y2 * 298;
3322a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed b2 = (tmp2 + u_b) / 256;
3332a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed g2 = (tmp2 + v_g + u_g) / 256;
3341c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed r2 = (tmp2 + v_r) / 256;
3351c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
3361c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            uint32_t rgb1 =
3371c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber                ((kAdjustedClip[b1] >> 3) << 11)
3381c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber                | ((kAdjustedClip[g1] >> 2) << 5)
3391c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber                | (kAdjustedClip[r1] >> 3);
3401c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
3411c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            uint32_t rgb2 =
3421c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber                ((kAdjustedClip[b2] >> 3) << 11)
3431c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber                | ((kAdjustedClip[g2] >> 2) << 5)
3441c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber                | (kAdjustedClip[r2] >> 3);
3451c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
3464e260ab948787c2a814543077832847deae890fdJames Dong            if (x + 1 < src.cropWidth()) {
3474e260ab948787c2a814543077832847deae890fdJames Dong                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
3484e260ab948787c2a814543077832847deae890fdJames Dong            } else {
3494e260ab948787c2a814543077832847deae890fdJames Dong                dst_ptr[x] = rgb1;
3504e260ab948787c2a814543077832847deae890fdJames Dong            }
3511c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber        }
3521c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
353f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        src_y += src.mWidth;
3541c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
3551c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber        if (y & 1) {
356f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            src_u += src.mWidth;
3571c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber        }
3581c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
3594e260ab948787c2a814543077832847deae890fdJames Dong        dst_ptr += dst.mWidth;
3601c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber    }
3611472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber
3621472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    return OK;
3631c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber}
3641c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
3651472eb39f7516faa26de200d8592464c8aaac38eAndreas Huberstatus_t ColorConverter::convertYUV420SemiPlanar(
366f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        const BitmapParams &src, const BitmapParams &dst) {
367f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    // XXX Untested
3681c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
3691c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber    uint8_t *kAdjustedClip = initClip();
3701c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
3714e260ab948787c2a814543077832847deae890fdJames Dong    if (!((src.mCropLeft & 1) == 0
3721472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber            && src.cropWidth() == dst.cropWidth()
3731472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber            && src.cropHeight() == dst.cropHeight())) {
3741472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber        return ERROR_UNSUPPORTED;
3751472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    }
376f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
3774e260ab948787c2a814543077832847deae890fdJames Dong    uint16_t *dst_ptr = (uint16_t *)dst.mBits
3784e260ab948787c2a814543077832847deae890fdJames Dong        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
379f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber
380f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    const uint8_t *src_y =
381f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
3821c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
3831c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber    const uint8_t *src_u =
384f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        (const uint8_t *)src_y + src.mWidth * src.mHeight
385f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        + src.mCropTop * src.mWidth + src.mCropLeft;
3861c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
387f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber    for (size_t y = 0; y < src.cropHeight(); ++y) {
388f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        for (size_t x = 0; x < src.cropWidth(); x += 2) {
3891c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed y1 = (signed)src_y[x] - 16;
3901c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed y2 = (signed)src_y[x + 1] - 16;
3911c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
3921c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed v = (signed)src_u[x & ~1] - 128;
3931c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed u = (signed)src_u[(x & ~1) + 1] - 128;
3941c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
3951c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed u_b = u * 517;
3961c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed u_g = -u * 100;
3971c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed v_g = -v * 208;
3981c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed v_r = v * 409;
3991c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
4001c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed tmp1 = y1 * 298;
4011c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed b1 = (tmp1 + u_b) / 256;
4021c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed g1 = (tmp1 + v_g + u_g) / 256;
4031c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed r1 = (tmp1 + v_r) / 256;
4041c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber
4051c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed tmp2 = y2 * 298;
4061c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed b2 = (tmp2 + u_b) / 256;
4071c8ed2e906576fd8d7fa03f577bdec518cbe13d7Andreas Huber            signed g2 = (tmp2 + v_g + u_g) / 256;
4082a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            signed r2 = (tmp2 + v_r) / 256;
4092a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4102a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            uint32_t rgb1 =
4112a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                ((kAdjustedClip[b1] >> 3) << 11)
4122a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | ((kAdjustedClip[g1] >> 2) << 5)
4132a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | (kAdjustedClip[r1] >> 3);
4142a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4152a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            uint32_t rgb2 =
4162a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                ((kAdjustedClip[b2] >> 3) << 11)
4172a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | ((kAdjustedClip[g2] >> 2) << 5)
4182a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber                | (kAdjustedClip[r2] >> 3);
4192a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4204e260ab948787c2a814543077832847deae890fdJames Dong            if (x + 1 < src.cropWidth()) {
4214e260ab948787c2a814543077832847deae890fdJames Dong                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
4224e260ab948787c2a814543077832847deae890fdJames Dong            } else {
4234e260ab948787c2a814543077832847deae890fdJames Dong                dst_ptr[x] = rgb1;
4244e260ab948787c2a814543077832847deae890fdJames Dong            }
4252a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        }
4262a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
427f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber        src_y += src.mWidth;
4282a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4292a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        if (y & 1) {
430f5ab57c2d5e02af7483c94eddb177e4f5c9e9892Andreas Huber            src_u += src.mWidth;
4312a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        }
4322a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
4334e260ab948787c2a814543077832847deae890fdJames Dong        dst_ptr += dst.mWidth;
4342a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    }
4351472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber
4361472eb39f7516faa26de200d8592464c8aaac38eAndreas Huber    return OK;
4372a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
4382a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
439cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajanstatus_t ColorConverter::convertTIYUV420PackedSemiPlanar(
440cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan        const BitmapParams &src, const BitmapParams &dst) {
4413571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber    uint8_t *kAdjustedClip = initClip();
442cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
4434e260ab948787c2a814543077832847deae890fdJames Dong    if (!((src.mCropLeft & 1) == 0
4443571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber            && src.cropWidth() == dst.cropWidth()
4453571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber            && src.cropHeight() == dst.cropHeight())) {
4463571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber        return ERROR_UNSUPPORTED;
4473571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber    }
448cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
4494e260ab948787c2a814543077832847deae890fdJames Dong    uint16_t *dst_ptr = (uint16_t *)dst.mBits
4504e260ab948787c2a814543077832847deae890fdJames Dong        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
451cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
452cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan    const uint8_t *src_y = (const uint8_t *)src.mBits;
453cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
4543571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber    const uint8_t *src_u =
4553571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber        (const uint8_t *)src_y + src.mWidth * (src.mHeight - src.mCropTop / 2);
456cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
4573571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber    for (size_t y = 0; y < src.cropHeight(); ++y) {
4583571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber        for (size_t x = 0; x < src.cropWidth(); x += 2) {
4593571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber            signed y1 = (signed)src_y[x] - 16;
4603571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber            signed y2 = (signed)src_y[x + 1] - 16;
461cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
4623571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber            signed u = (signed)src_u[x & ~1] - 128;
4633571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber            signed v = (signed)src_u[(x & ~1) + 1] - 128;
464cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
465cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed u_b = u * 517;
466cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed u_g = -u * 100;
467cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed v_g = -v * 208;
468cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed v_r = v * 409;
469cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
470cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed tmp1 = y1 * 298;
471cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed b1 = (tmp1 + u_b) / 256;
472cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed g1 = (tmp1 + v_g + u_g) / 256;
473cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed r1 = (tmp1 + v_r) / 256;
474cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
475cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed tmp2 = y2 * 298;
476cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed b2 = (tmp2 + u_b) / 256;
477cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed g2 = (tmp2 + v_g + u_g) / 256;
478cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            signed r2 = (tmp2 + v_r) / 256;
479cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
480cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            uint32_t rgb1 =
481cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan                ((kAdjustedClip[r1] >> 3) << 11)
482cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan                | ((kAdjustedClip[g1] >> 2) << 5)
483cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan                | (kAdjustedClip[b1] >> 3);
484cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
485cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan            uint32_t rgb2 =
486cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan                ((kAdjustedClip[r2] >> 3) << 11)
4873571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber                | ((kAdjustedClip[g2] >> 2) << 5)
4883571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber                | (kAdjustedClip[b2] >> 3);
489cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
4904e260ab948787c2a814543077832847deae890fdJames Dong            if (x + 1 < src.cropWidth()) {
4914e260ab948787c2a814543077832847deae890fdJames Dong                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
4924e260ab948787c2a814543077832847deae890fdJames Dong            } else {
4934e260ab948787c2a814543077832847deae890fdJames Dong                dst_ptr[x] = rgb1;
4944e260ab948787c2a814543077832847deae890fdJames Dong            }
495cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan        }
496cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
4973571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber        src_y += src.mWidth;
4983571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber
4993571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber        if (y & 1) {
5003571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber            src_u += src.mWidth;
501cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan        }
502cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
5034e260ab948787c2a814543077832847deae890fdJames Dong        dst_ptr += dst.mWidth;
504cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan    }
5053571d50a2582bc9c63f09cd81b4f490ea3522bd9Andreas Huber
506cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan    return OK;
507cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan}
508cb62bc3fe54222cf05824e6f98fefafee552049aAnu Sundararajan
5092a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huberuint8_t *ColorConverter::initClip() {
5102a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    static const signed kClipMin = -278;
5112a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    static const signed kClipMax = 535;
5122a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
5132a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    if (mClip == NULL) {
5142a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        mClip = new uint8_t[kClipMax - kClipMin + 1];
5152a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
5162a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        for (signed i = kClipMin; i <= kClipMax; ++i) {
5172a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber            mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
5182a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber        }
5192a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    }
5202a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
5212a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber    return &mClip[-kClipMin];
5222a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}
5232a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber
5242a4a7d5af053a17586a262a1267ba993e31790f1Andreas Huber}  // namespace android
525