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
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 3370df1..c0e65e8 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -528,6 +528,18 @@
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 @@
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;
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index c46a40f..862cc63 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -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::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 @@
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 @@
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;
diff --git a/media/libstagefright/include/media/stagefright/ColorConverter.h b/media/libstagefright/include/media/stagefright/ColorConverter.h
index 2b8c7c8..6d4c1bf 100644
--- a/media/libstagefright/include/media/stagefright/ColorConverter.h
+++ b/media/libstagefright/include/media/stagefright/ColorConverter.h
@@ -35,6 +35,8 @@
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 @@
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 @@
};
OMX_COLOR_FORMATTYPE mSrcFormat, mDstFormat;
+ ColorSpace mSrcColorSpace;
uint8_t *mClip;
uint8_t *initClip();