153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber/*
253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber * Copyright (C) 2009 The Android Open Source Project
353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber *
453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber * you may not use this file except in compliance with the License.
653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber * You may obtain a copy of the License at
753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber *
853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber *
1053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber * Unless required by applicable law or agreed to in writing, software
1153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
1253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber * See the License for the specific language governing permissions and
1453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber * limitations under the License.
1553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber */
1653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
1753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber#include <media/stagefright/ColorConverter.h>
1853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber#include <media/stagefright/MediaDebug.h>
1953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
2053a76bd0c918082847e52570c307ed3ba325992dAndreas Hubernamespace android {
2153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
2253a76bd0c918082847e52570c307ed3ba325992dAndreas Huberstatic const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
2353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
2453a76bd0c918082847e52570c307ed3ba325992dAndreas HuberColorConverter::ColorConverter(
2553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to)
2653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    : mSrcFormat(from),
2753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber      mDstFormat(to),
2853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber      mClip(NULL) {
2953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber}
3053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
3153a76bd0c918082847e52570c307ed3ba325992dAndreas HuberColorConverter::~ColorConverter() {
3253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    delete[] mClip;
3353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    mClip = NULL;
3453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber}
3553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
3653a76bd0c918082847e52570c307ed3ba325992dAndreas Huberbool ColorConverter::isValid() const {
3753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    if (mDstFormat != OMX_COLOR_Format16bitRGB565) {
3853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        return false;
3953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    }
4053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
4153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    switch (mSrcFormat) {
4253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        case OMX_COLOR_FormatYUV420Planar:
4353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        case OMX_COLOR_FormatCbYCrY:
4453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
45c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber        case OMX_COLOR_FormatYUV420SemiPlanar:
4653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            return true;
4753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
4853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        default:
4953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            return false;
5053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    }
5153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber}
5253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
5353a76bd0c918082847e52570c307ed3ba325992dAndreas Hubervoid ColorConverter::convert(
5453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        size_t width, size_t height,
5553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        const void *srcBits, size_t srcSkip,
5653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        void *dstBits, size_t dstSkip) {
5753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    CHECK_EQ(mDstFormat, OMX_COLOR_Format16bitRGB565);
5853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
5953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    switch (mSrcFormat) {
6053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        case OMX_COLOR_FormatYUV420Planar:
6153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            convertYUV420Planar(
6253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                    width, height, srcBits, srcSkip, dstBits, dstSkip);
6353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            break;
6453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
6553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        case OMX_COLOR_FormatCbYCrY:
6653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            convertCbYCrY(
6753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                    width, height, srcBits, srcSkip, dstBits, dstSkip);
6853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            break;
6953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
7053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
7153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            convertQCOMYUV420SemiPlanar(
7253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                    width, height, srcBits, srcSkip, dstBits, dstSkip);
7353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            break;
7453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
75c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber        case OMX_COLOR_FormatYUV420SemiPlanar:
76c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            convertYUV420SemiPlanar(
77c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber                    width, height, srcBits, srcSkip, dstBits, dstSkip);
78c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            break;
79c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
8053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        default:
8153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        {
8253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            CHECK(!"Should not be here. Unknown color conversion.");
8353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            break;
8453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        }
8553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    }
8653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber}
8753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
8853a76bd0c918082847e52570c307ed3ba325992dAndreas Hubervoid ColorConverter::convertCbYCrY(
8953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        size_t width, size_t height,
9053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        const void *srcBits, size_t srcSkip,
9153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        void *dstBits, size_t dstSkip) {
9253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    CHECK_EQ(srcSkip, 0);  // Doesn't really make sense for YUV formats.
9353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    CHECK(dstSkip >= width * 2);
9453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    CHECK((dstSkip & 3) == 0);
9553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
9653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    uint8_t *kAdjustedClip = initClip();
9753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
9853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    uint32_t *dst_ptr = (uint32_t *)dstBits;
9953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
10053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    const uint8_t *src = (const uint8_t *)srcBits;
10153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
10253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    for (size_t y = 0; y < height; ++y) {
10353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        for (size_t x = 0; x < width; x += 2) {
10453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed y1 = (signed)src[2 * x + 1] - 16;
10553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed y2 = (signed)src[2 * x + 3] - 16;
10653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed u = (signed)src[2 * x] - 128;
10753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed v = (signed)src[2 * x + 2] - 128;
10853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
10953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed u_b = u * 517;
11053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed u_g = -u * 100;
11153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed v_g = -v * 208;
11253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed v_r = v * 409;
11353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
11453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed tmp1 = y1 * 298;
11553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed b1 = (tmp1 + u_b) / 256;
11653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed g1 = (tmp1 + v_g + u_g) / 256;
11753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed r1 = (tmp1 + v_r) / 256;
11853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
11953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed tmp2 = y2 * 298;
12053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed b2 = (tmp2 + u_b) / 256;
12153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed g2 = (tmp2 + v_g + u_g) / 256;
12253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed r2 = (tmp2 + v_r) / 256;
12353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
12453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            uint32_t rgb1 =
12553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                ((kAdjustedClip[r1] >> 3) << 11)
12653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                | ((kAdjustedClip[g1] >> 2) << 5)
12753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                | (kAdjustedClip[b1] >> 3);
12853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
12953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            uint32_t rgb2 =
13053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                ((kAdjustedClip[r2] >> 3) << 11)
13153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                | ((kAdjustedClip[g2] >> 2) << 5)
13253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                | (kAdjustedClip[b2] >> 3);
13353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
13453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
13553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        }
13653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
13753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        src += width * 2;
13853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        dst_ptr += dstSkip / 4;
13953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    }
14053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber}
14153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
14253a76bd0c918082847e52570c307ed3ba325992dAndreas Hubervoid ColorConverter::convertYUV420Planar(
14353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        size_t width, size_t height,
14453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        const void *srcBits, size_t srcSkip,
14553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        void *dstBits, size_t dstSkip) {
14653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    CHECK_EQ(srcSkip, 0);  // Doesn't really make sense for YUV formats.
14753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    CHECK(dstSkip >= width * 2);
14853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    CHECK((dstSkip & 3) == 0);
14953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
15053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    uint8_t *kAdjustedClip = initClip();
15153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
15253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    uint32_t *dst_ptr = (uint32_t *)dstBits;
15353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    const uint8_t *src_y = (const uint8_t *)srcBits;
15453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
15553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    const uint8_t *src_u =
15653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        (const uint8_t *)src_y + width * height;
15753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
15853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    const uint8_t *src_v =
15953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        (const uint8_t *)src_u + (width / 2) * (height / 2);
16053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
16153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    for (size_t y = 0; y < height; ++y) {
16253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        for (size_t x = 0; x < width; x += 2) {
16353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            // B = 1.164 * (Y - 16) + 2.018 * (U - 128)
16453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128)
16553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            // R = 1.164 * (Y - 16) + 1.596 * (V - 128)
16653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
16753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            // B = 298/256 * (Y - 16) + 517/256 * (U - 128)
16853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128)
16953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            // R = .................. + 409/256 * (V - 128)
17053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
17153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277
17253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172
17353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223
17453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
17553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534
17653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432
17753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481
17853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
17953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            // clip range -278 .. 535
18053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
18153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed y1 = (signed)src_y[x] - 16;
18253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed y2 = (signed)src_y[x + 1] - 16;
18353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
18453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed u = (signed)src_u[x / 2] - 128;
18553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed v = (signed)src_v[x / 2] - 128;
18653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
18753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed u_b = u * 517;
18853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed u_g = -u * 100;
18953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed v_g = -v * 208;
19053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed v_r = v * 409;
19153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
19253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed tmp1 = y1 * 298;
19353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed b1 = (tmp1 + u_b) / 256;
19453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed g1 = (tmp1 + v_g + u_g) / 256;
19553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed r1 = (tmp1 + v_r) / 256;
19653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
19753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed tmp2 = y2 * 298;
19853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed b2 = (tmp2 + u_b) / 256;
19953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed g2 = (tmp2 + v_g + u_g) / 256;
20053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed r2 = (tmp2 + v_r) / 256;
20153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
20253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            uint32_t rgb1 =
20353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                ((kAdjustedClip[r1] >> 3) << 11)
20453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                | ((kAdjustedClip[g1] >> 2) << 5)
20553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                | (kAdjustedClip[b1] >> 3);
20653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
20753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            uint32_t rgb2 =
20853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                ((kAdjustedClip[r2] >> 3) << 11)
20953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                | ((kAdjustedClip[g2] >> 2) << 5)
21053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                | (kAdjustedClip[b2] >> 3);
21153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
21253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
21353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        }
21453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
21553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        src_y += width;
21653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
21753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        if (y & 1) {
21853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            src_u += width / 2;
21953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            src_v += width / 2;
22053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        }
22153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
22253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        dst_ptr += dstSkip / 4;
22353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    }
22453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber}
22553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
22653a76bd0c918082847e52570c307ed3ba325992dAndreas Hubervoid ColorConverter::convertQCOMYUV420SemiPlanar(
22753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        size_t width, size_t height,
22853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        const void *srcBits, size_t srcSkip,
22953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        void *dstBits, size_t dstSkip) {
23053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    CHECK_EQ(srcSkip, 0);  // Doesn't really make sense for YUV formats.
23153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    CHECK(dstSkip >= width * 2);
23253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    CHECK((dstSkip & 3) == 0);
23353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
23453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    uint8_t *kAdjustedClip = initClip();
23553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
23653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    uint32_t *dst_ptr = (uint32_t *)dstBits;
23753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    const uint8_t *src_y = (const uint8_t *)srcBits;
23853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
23953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    const uint8_t *src_u =
24053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        (const uint8_t *)src_y + width * height;
24153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
24253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    for (size_t y = 0; y < height; ++y) {
24353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        for (size_t x = 0; x < width; x += 2) {
24453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed y1 = (signed)src_y[x] - 16;
24553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed y2 = (signed)src_y[x + 1] - 16;
24653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
24753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed u = (signed)src_u[x & ~1] - 128;
24853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed v = (signed)src_u[(x & ~1) + 1] - 128;
24953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
25053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed u_b = u * 517;
25153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed u_g = -u * 100;
25253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed v_g = -v * 208;
25353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed v_r = v * 409;
25453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
25553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed tmp1 = y1 * 298;
25653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed b1 = (tmp1 + u_b) / 256;
25753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed g1 = (tmp1 + v_g + u_g) / 256;
25853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed r1 = (tmp1 + v_r) / 256;
25953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
26053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed tmp2 = y2 * 298;
26153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed b2 = (tmp2 + u_b) / 256;
26253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed g2 = (tmp2 + v_g + u_g) / 256;
263c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed r2 = (tmp2 + v_r) / 256;
264c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
265c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            uint32_t rgb1 =
266c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber                ((kAdjustedClip[b1] >> 3) << 11)
267c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber                | ((kAdjustedClip[g1] >> 2) << 5)
268c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber                | (kAdjustedClip[r1] >> 3);
269c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
270c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            uint32_t rgb2 =
271c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber                ((kAdjustedClip[b2] >> 3) << 11)
272c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber                | ((kAdjustedClip[g2] >> 2) << 5)
273c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber                | (kAdjustedClip[r2] >> 3);
274c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
275c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
276c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber        }
277c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
278c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber        src_y += width;
279c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
280c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber        if (y & 1) {
281c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            src_u += width;
282c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber        }
283c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
284c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber        dst_ptr += dstSkip / 4;
285c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber    }
286c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber}
287c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
288c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Hubervoid ColorConverter::convertYUV420SemiPlanar(
289c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber        size_t width, size_t height,
290c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber        const void *srcBits, size_t srcSkip,
291c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber        void *dstBits, size_t dstSkip) {
292c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber    CHECK_EQ(srcSkip, 0);  // Doesn't really make sense for YUV formats.
293c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber    CHECK(dstSkip >= width * 2);
294c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber    CHECK((dstSkip & 3) == 0);
295c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
296c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber    uint8_t *kAdjustedClip = initClip();
297c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
298c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber    uint32_t *dst_ptr = (uint32_t *)dstBits;
299c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber    const uint8_t *src_y = (const uint8_t *)srcBits;
300c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
301c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber    const uint8_t *src_u =
302c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber        (const uint8_t *)src_y + width * height;
303c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
304c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber    for (size_t y = 0; y < height; ++y) {
305c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber        for (size_t x = 0; x < width; x += 2) {
306c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed y1 = (signed)src_y[x] - 16;
307c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed y2 = (signed)src_y[x + 1] - 16;
308c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
309c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed v = (signed)src_u[x & ~1] - 128;
310c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed u = (signed)src_u[(x & ~1) + 1] - 128;
311c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
312c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed u_b = u * 517;
313c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed u_g = -u * 100;
314c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed v_g = -v * 208;
315c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed v_r = v * 409;
316c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
317c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed tmp1 = y1 * 298;
318c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed b1 = (tmp1 + u_b) / 256;
319c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed g1 = (tmp1 + v_g + u_g) / 256;
320c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed r1 = (tmp1 + v_r) / 256;
321c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber
322c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed tmp2 = y2 * 298;
323c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed b2 = (tmp2 + u_b) / 256;
324c543a21a4021bf0e2f3817852d75184d01b76d62Andreas Huber            signed g2 = (tmp2 + v_g + u_g) / 256;
32553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            signed r2 = (tmp2 + v_r) / 256;
32653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
32753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            uint32_t rgb1 =
32853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                ((kAdjustedClip[b1] >> 3) << 11)
32953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                | ((kAdjustedClip[g1] >> 2) << 5)
33053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                | (kAdjustedClip[r1] >> 3);
33153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
33253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            uint32_t rgb2 =
33353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                ((kAdjustedClip[b2] >> 3) << 11)
33453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                | ((kAdjustedClip[g2] >> 2) << 5)
33553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber                | (kAdjustedClip[r2] >> 3);
33653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
33753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
33853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        }
33953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
34053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        src_y += width;
34153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
34253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        if (y & 1) {
34353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            src_u += width;
34453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        }
34553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
34653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        dst_ptr += dstSkip / 4;
34753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    }
34853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber}
34953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
35053a76bd0c918082847e52570c307ed3ba325992dAndreas Huberuint8_t *ColorConverter::initClip() {
35153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    static const signed kClipMin = -278;
35253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    static const signed kClipMax = 535;
35353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
35453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    if (mClip == NULL) {
35553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        mClip = new uint8_t[kClipMax - kClipMin + 1];
35653a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
35753a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        for (signed i = kClipMin; i <= kClipMax; ++i) {
35853a76bd0c918082847e52570c307ed3ba325992dAndreas Huber            mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
35953a76bd0c918082847e52570c307ed3ba325992dAndreas Huber        }
36053a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    }
36153a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
36253a76bd0c918082847e52570c307ed3ba325992dAndreas Huber    return &mClip[-kClipMin];
36353a76bd0c918082847e52570c307ed3ba325992dAndreas Huber}
36453a76bd0c918082847e52570c307ed3ba325992dAndreas Huber
36553a76bd0c918082847e52570c307ed3ba325992dAndreas Huber}  // namespace android
366