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

Commit df79be32 authored by Chong Zhang's avatar Chong Zhang
Browse files

Choose color conversion matrix for color space

When doing the YUV->RGB conversion in image/video frame
decoder, choose the libyuv function that uses the color
matrix that matches the source color space.

bug: 109762970
Test: - bitmap decoding of HEIF images;
- video thumbnail extraction in Photos app, observe
color of thumbnail vs video playback

Change-Id: Id11cb192a45bb2a5c3944ba7f99f599ca851b0d2
parent 965737ed
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -528,6 +528,18 @@ status_t VideoFrameDecoder::onOutputReceived(

    ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());

    uint32_t standard, range, transfer;
    if (!outputFormat->findInt32("color-standard", (int32_t*)&standard)) {
        standard = 0;
    }
    if (!outputFormat->findInt32("color-range", (int32_t*)&range)) {
        range = 0;
    }
    if (!outputFormat->findInt32("color-transfer", (int32_t*)&transfer)) {
        transfer = 0;
    }
    converter.setSrcColorSpace(standard, range, transfer);

    if (converter.isValid()) {
        converter.convert(
                (const uint8_t *)videoFrameBuffer->data(),
@@ -699,6 +711,18 @@ status_t ImageDecoder::onOutputReceived(

    ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());

    uint32_t standard, range, transfer;
    if (!outputFormat->findInt32("color-standard", (int32_t*)&standard)) {
        standard = 0;
    }
    if (!outputFormat->findInt32("color-range", (int32_t*)&range)) {
        range = 0;
    }
    if (!outputFormat->findInt32("color-transfer", (int32_t*)&transfer)) {
        transfer = 0;
    }
    converter.setSrcColorSpace(standard, range, transfer);

    int32_t dstLeft, dstTop, dstRight, dstBottom;
    dstLeft = mTilesDecoded % mGridCols * width;
    dstTop = mTilesDecoded / mGridCols * height;
+53 −8
Original line number Diff line number Diff line
@@ -20,10 +20,12 @@

#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/ColorUtils.h>
#include <media/stagefright/ColorConverter.h>
#include <media/stagefright/MediaErrors.h>

#include "libyuv/convert_from.h"
#include "libyuv/convert_argb.h"
#include "libyuv/video_common.h"
#include <functional>
#include <sys/time.h>
@@ -44,10 +46,28 @@

namespace android {

static bool isRGB(OMX_COLOR_FORMATTYPE colorFormat) {
    return colorFormat == OMX_COLOR_Format16bitRGB565
            || colorFormat == OMX_COLOR_Format32BitRGBA8888
            || colorFormat == OMX_COLOR_Format32bitBGRA8888;
}

bool ColorConverter::ColorSpace::isBt709() {
    return (mStandard == ColorUtils::kColorStandardBT709);
}


bool ColorConverter::ColorSpace::isJpeg() {
    return ((mStandard == ColorUtils::kColorStandardBT601_625)
            || (mStandard == ColorUtils::kColorStandardBT601_525))
            && (mRange == ColorUtils::kColorRangeFull);
}

ColorConverter::ColorConverter(
        OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to)
    : mSrcFormat(from),
      mDstFormat(to),
      mSrcColorSpace({0, 0, 0}),
      mClip(NULL) {
}

@@ -80,9 +100,18 @@ bool ColorConverter::isValid() const {
}

bool ColorConverter::isDstRGB() const {
    return mDstFormat == OMX_COLOR_Format16bitRGB565
            || mDstFormat == OMX_COLOR_Format32BitRGBA8888
            || mDstFormat == OMX_COLOR_Format32bitBGRA8888;
    return isRGB(mDstFormat);
}

void ColorConverter::setSrcColorSpace(
        uint32_t standard, uint32_t range, uint32_t transfer) {
    if (isRGB(mSrcFormat)) {
        ALOGW("Can't set color space on RGB source");
        return;
    }
    mSrcColorSpace.mStandard = standard;
    mSrcColorSpace.mRange = range;
    mSrcColorSpace.mTransfer = transfer;
}

/*
@@ -281,6 +310,13 @@ status_t ColorConverter::convertCbYCrY(
    return OK;
}

#define DECLARE_YUV2RGBFUNC(func, rgb) int (*func)(     \
        const uint8*, int, const uint8*, int,           \
        const uint8*, int, uint8*, int, int, int)       \
        = mSrcColorSpace.isBt709() ? libyuv::H420To##rgb \
        : mSrcColorSpace.isJpeg() ? libyuv::J420To##rgb  \
        : libyuv::I420To##rgb

status_t ColorConverter::convertYUV420PlanarUseLibYUV(
        const BitmapParams &src, const BitmapParams &dst) {
    uint8_t *dst_ptr = (uint8_t *)dst.mBits
@@ -298,19 +334,28 @@ status_t ColorConverter::convertYUV420PlanarUseLibYUV(

    switch (mDstFormat) {
    case OMX_COLOR_Format16bitRGB565:
        libyuv::I420ToRGB565(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
    {
        DECLARE_YUV2RGBFUNC(func, RGB565);
        (*func)(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
        break;
    }

    case OMX_COLOR_Format32BitRGBA8888:
        libyuv::ConvertFromI420(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight(), libyuv::FOURCC_ABGR);
    {
        DECLARE_YUV2RGBFUNC(func, ABGR);
        (*func)(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
        break;
    }

    case OMX_COLOR_Format32bitBGRA8888:
        libyuv::ConvertFromI420(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight(), libyuv::FOURCC_ARGB);
    {
        DECLARE_YUV2RGBFUNC(func, ARGB);
        (*func)(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
        break;
    }

    default:
        return ERROR_UNSUPPORTED;
+12 −0
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ struct ColorConverter {

    bool isDstRGB() const;

    void setSrcColorSpace(uint32_t standard, uint32_t range, uint32_t transfer);

    status_t convert(
            const void *srcBits,
            size_t srcWidth, size_t srcHeight, size_t srcStride,
@@ -46,6 +48,15 @@ struct ColorConverter {
            size_t dstCropRight, size_t dstCropBottom);

private:
    struct ColorSpace {
        uint32_t mStandard;
        uint32_t mRange;
        uint32_t mTransfer;

        bool isBt709();
        bool isJpeg();
    };

    struct BitmapParams {
        BitmapParams(
                void *bits,
@@ -65,6 +76,7 @@ private:
    };

    OMX_COLOR_FORMATTYPE mSrcFormat, mDstFormat;
    ColorSpace mSrcColorSpace;
    uint8_t *mClip;

    uint8_t *initClip();