Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f234579 authored by Andreas Huber's avatar Andreas Huber
Browse files

Another software color conversion implementation, this time...

Another software color conversion implementation, this time OMX_QCOM_COLOR_FormatYVU420SemiPlanar => rgb565.
parent a4fe2aca
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ private:

    void renderCbYCrY(const void *data, size_t size);
    void renderYUV420Planar(const void *data, size_t size);
    void renderQCOMYUV420SemiPlanar(const void *data, size_t size);

    OMX_COLOR_FORMATTYPE mColorFormat;
    sp<ISurface> mISurface;
+75 −0
Original line number Diff line number Diff line
@@ -65,6 +65,8 @@ SoftwareRenderer::~SoftwareRenderer() {

void SoftwareRenderer::render(
        const void *data, size_t size, void *platformPrivate) {
    static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;

    switch (mColorFormat) {
        case OMX_COLOR_FormatYUV420Planar:
            return renderYUV420Planar(data, size);
@@ -72,6 +74,9 @@ void SoftwareRenderer::render(
        case OMX_COLOR_FormatCbYCrY:
            return renderCbYCrY(data, size);

        case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
            return renderQCOMYUV420SemiPlanar(data, size);

        default:
        {
            LOGW("Cannot render color format %ld", mColorFormat);
@@ -242,6 +247,76 @@ void SoftwareRenderer::renderCbYCrY(
    mIndex = 1 - mIndex;
}

void SoftwareRenderer::renderQCOMYUV420SemiPlanar(
        const void *data, size_t size) {
    if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) {
        LOGE("size is %d, expected %d",
                size, (mDecodedHeight * mDecodedWidth * 3) / 2);
    }
    CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);

    uint8_t *kAdjustedClip = initClip();

    size_t offset = mIndex * mFrameSize;

    void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;

    uint32_t *dst_ptr = (uint32_t *)dst;

    const uint8_t *src_y = (const uint8_t *)data;

    const uint8_t *src_u =
        (const uint8_t *)src_y + mDecodedWidth * mDecodedHeight;

    for (size_t y = 0; y < mDecodedHeight; ++y) {
        for (size_t x = 0; x < mDecodedWidth; x += 2) {
            signed y1 = (signed)src_y[x] - 16;
            signed y2 = (signed)src_y[x + 1] - 16;

            signed u = (signed)src_u[x & ~1] - 128;
            signed v = (signed)src_u[(x & ~1) + 1] - 128;

            signed u_b = u * 517;
            signed u_g = -u * 100;
            signed v_g = -v * 208;
            signed v_r = v * 409;

            signed tmp1 = y1 * 298;
            signed b1 = (tmp1 + u_b) / 256;
            signed g1 = (tmp1 + v_g + u_g) / 256;
            signed r1 = (tmp1 + v_r) / 256;

            signed tmp2 = y2 * 298;
            signed b2 = (tmp2 + u_b) / 256;
            signed g2 = (tmp2 + v_g + u_g) / 256;
            signed r2 = (tmp2 + v_r) / 256;

            uint32_t rgb1 =
                ((kAdjustedClip[b1] >> 3) << 11)
                | ((kAdjustedClip[g1] >> 2) << 5)
                | (kAdjustedClip[r1] >> 3);

            uint32_t rgb2 =
                ((kAdjustedClip[b2] >> 3) << 11)
                | ((kAdjustedClip[g2] >> 2) << 5)
                | (kAdjustedClip[r2] >> 3);

            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
        }

        src_y += mDecodedWidth;

        if (y & 1) {
            src_u += mDecodedWidth;
        }

        dst_ptr += mDecodedWidth / 2;
    }

    mISurface->postBuffer(offset);
    mIndex = 1 - mIndex;
}

uint8_t *SoftwareRenderer::initClip() {
    static const signed kClipMin = -278;
    static const signed kClipMax = 535;