From a07266fa42f6803053b2175dbb19bb1fccc040c6 Mon Sep 17 00:00:00 2001 From: roytam1 Date: Mon, 27 Feb 2023 13:26:46 +0800 Subject: [PATCH] ported from UXP: Issue #2118 - Part 2: Add support for Identity YUVColorSpace (3e62b1fc) --- dom/media/platforms/agnostic/AOMDecoder.cpp | 15 ++++++ dom/media/platforms/agnostic/VPXDecoder.cpp | 16 ++++++ .../platforms/ffmpeg/FFmpegVideoDecoder.cpp | 10 +++- gfx/layers/ImageTypes.h | 1 + gfx/thebes/gfxUtils.cpp | 10 ++++ gfx/ycbcr/yuv_convert.cpp | 54 ++++++++++++++++--- 6 files changed, 98 insertions(+), 8 deletions(-) diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp index b5d21375e..693b98c94 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.cpp +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -232,6 +232,21 @@ AOMDecoder::DoDecode(MediaRawData* aSample) RESULT_DETAIL("AOM Unknown image format")); } + switch (img->mc) { + case AOM_CICP_MC_BT_601: + b.mYUVColorSpace = YUVColorSpace::BT601; + break; + case AOM_CICP_MC_BT_709: + b.mYUVColorSpace = YUVColorSpace::BT709; + break; + case AOM_CICP_MC_IDENTITY: + b.mYUVColorSpace = YUVColorSpace::IDENTITY; + break; + default: + LOG("Unhandled colorspace %d", img->mc); + break; + } + RefPtr v = VideoData::CreateAndCopyData(mInfo, mImageContainer, diff --git a/dom/media/platforms/agnostic/VPXDecoder.cpp b/dom/media/platforms/agnostic/VPXDecoder.cpp index 77de89c3c..21820187a 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.cpp +++ b/dom/media/platforms/agnostic/VPXDecoder.cpp @@ -194,6 +194,22 @@ VPXDecoder::DoDecode(MediaRawData* aSample) RESULT_DETAIL("VPX Unknown image format")); } + b.mYUVColorSpace = [&]() { + switch (img->cs) { + case VPX_CS_BT_601: + case VPX_CS_SMPTE_170: + case VPX_CS_SMPTE_240: + return YUVColorSpace::BT601; + case VPX_CS_BT_709: + return YUVColorSpace::BT709; + case VPX_CS_SRGB: + return YUVColorSpace::IDENTITY; + default: + LOG("Unhandled colorspace %d", img->cs); + return YUVColorSpace::BT601; + } + }(); + RefPtr v; if (!img_alpha) { v = VideoData::CreateAndCopyData(mInfo, diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp index a93eab272..21562e16e 100644 --- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp @@ -23,6 +23,7 @@ #define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P #define AV_PIX_FMT_YUVJ420P PIX_FMT_YUVJ420P #define AV_PIX_FMT_YUV444P PIX_FMT_YUV444P +#define AV_PIX_FMT_GBRP PIX_FMT_GBRP #define AV_PIX_FMT_NONE PIX_FMT_NONE #endif @@ -53,6 +54,9 @@ ChoosePixelFormat(AVCodecContext* aCodecContext, const AVPixelFormat* aFormats) case AV_PIX_FMT_YUVJ420P: FFMPEG_LOG("Requesting pixel format YUVJ420P."); return AV_PIX_FMT_YUVJ420P; + case AV_PIX_FMT_GBRP: + FFMPEG_LOG("Requesting pixel format GBRP."); + return AV_PIX_FMT_GBRP; default: break; } @@ -294,7 +298,8 @@ FFmpegVideoDecoder::DoDecode(MediaRawData* aSample, b.mPlanes[0].mWidth = mFrame->width; b.mPlanes[0].mHeight = mFrame->height; - if (mCodecContext->pix_fmt == AV_PIX_FMT_YUV444P) { + if (mCodecContext->pix_fmt == AV_PIX_FMT_YUV444P || + mCodecContext->pix_fmt == AV_PIX_FMT_GBRP) { b.mPlanes[1].mWidth = b.mPlanes[2].mWidth = mFrame->width; b.mPlanes[1].mHeight = b.mPlanes[2].mHeight = mFrame->height; } else { @@ -310,6 +315,9 @@ FFmpegVideoDecoder::DoDecode(MediaRawData* aSample, case AVCOL_SPC_BT470BG: b.mYUVColorSpace = YUVColorSpace::BT601; break; + case AVCOL_SPC_RGB: + b.mYUVColorSpace = YUVColorSpace::IDENTITY; + break; case AVCOL_SPC_UNSPECIFIED: #if LIBAVCODEC_VERSION_MAJOR >= 55 if (mCodecContext->codec_id == AV_CODEC_ID_VP9) { diff --git a/gfx/layers/ImageTypes.h b/gfx/layers/ImageTypes.h index 1ac29a003..ff301408e 100644 --- a/gfx/layers/ImageTypes.h +++ b/gfx/layers/ImageTypes.h @@ -101,6 +101,7 @@ enum class StereoMode { enum class YUVColorSpace { BT601, BT709, + IDENTITY, // This represents the unknown format. UNKNOWN, }; diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index ab42b3008..d003502ff 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -1157,6 +1157,10 @@ const float kBT709NarrowYCbCrToRGB_RowMajor[16] = { 1.16438f, 0.00000f, 1.79274f, -0.97295f, 1.16438f, -0.21325f, -0.53291f, 0.30148f, 1.16438f, 2.11240f, 0.00000f, -1.13340f, 0.00000f, 0.00000f, 0.00000f, 1.00000f}; +const float kIdentityNarrowYCbCrToRGB_RowMajor[16] = { + 0.00000f, 0.00000f, 1.00000f, 0.00000f, 1.00000f, 0.00000f, + 0.00000f, 0.00000f, 0.00000f, 1.00000f, 0.00000f, 0.00000f, + 0.00000f, 0.00000f, 0.00000f, 1.00000f}; /* static */ const float* gfxUtils::Get4x3YuvColorMatrix(YUVColorSpace aYUVColorSpace) @@ -1166,6 +1170,7 @@ gfxUtils::Get4x3YuvColorMatrix(YUVColorSpace aYUVColorSpace) static const float rec601[12] = X(kBT601NarrowYCbCrToRGB_RowMajor); static const float rec709[12] = X(kBT709NarrowYCbCrToRGB_RowMajor); + static const float identity[12] = X(kIdentityNarrowYCbCrToRGB_RowMajor); #undef X @@ -1174,6 +1179,8 @@ gfxUtils::Get4x3YuvColorMatrix(YUVColorSpace aYUVColorSpace) return rec601; case YUVColorSpace::BT709: return rec709; + case YUVColorSpace::IDENTITY: + return identity; default: MOZ_CRASH("Bad YUVColorSpace"); } @@ -1187,6 +1194,7 @@ gfxUtils::Get3x3YuvColorMatrix(YUVColorSpace aYUVColorSpace) static const float rec601[9] = X(kBT601NarrowYCbCrToRGB_RowMajor); static const float rec709[9] = X(kBT709NarrowYCbCrToRGB_RowMajor); + static const float identity[9] = X(kIdentityNarrowYCbCrToRGB_RowMajor); #undef X @@ -1195,6 +1203,8 @@ gfxUtils::Get3x3YuvColorMatrix(YUVColorSpace aYUVColorSpace) return rec601; case YUVColorSpace::BT709: return rec709; + case YUVColorSpace::IDENTITY: + return identity; default: MOZ_CRASH("Bad YUVColorSpace"); } diff --git a/gfx/ycbcr/yuv_convert.cpp b/gfx/ycbcr/yuv_convert.cpp index 5677d953d..4302a0515 100644 --- a/gfx/ycbcr/yuv_convert.cpp +++ b/gfx/ycbcr/yuv_convert.cpp @@ -24,6 +24,7 @@ // Header for low level row functions. #include "yuv_row.h" #include "mozilla/SSE.h" +#include "mozilla/IntegerRange.h" namespace mozilla { @@ -63,6 +64,23 @@ libyuv::FourCC FourCCFromYUVType(YUVType aYUVType) } } +void GBRPlanarToARGB(const uint8_t* src_y, int y_pitch, + const uint8_t* src_u, int u_pitch, + const uint8_t* src_v, int v_pitch, + uint8_t* rgb_buf, int rgb_pitch, + int pic_width, int pic_height) { + // libyuv has no native conversion function for this + // fixme: replace with something less awful + for (const auto row : IntegerRange(pic_height)) { + for (const auto col : IntegerRange(pic_width)) { + rgb_buf[rgb_pitch * row + col * 4 + 0] = src_u[u_pitch * row + col]; + rgb_buf[rgb_pitch * row + col * 4 + 1] = src_y[y_pitch * row + col]; + rgb_buf[rgb_pitch * row + col * 4 + 2] = src_v[v_pitch * row + col]; + rgb_buf[rgb_pitch * row + col * 4 + 3] = 255; + } + } +} + // Convert a frame of YUV to 32 bit ARGB. void ConvertYCbCrToRGB32(const uint8* y_buf, const uint8* u_buf, @@ -113,13 +131,20 @@ void ConvertYCbCrToRGB32(const uint8* y_buf, const uint8* src_y = y_buf + y_pitch * pic_y + pic_x; const uint8* src_u = u_buf + uv_pitch * pic_y + pic_x; const uint8* src_v = v_buf + uv_pitch * pic_y + pic_x; - DebugOnly err = libyuv::I444ToARGBMatrix(src_y, y_pitch, - src_u, uv_pitch, - src_v, uv_pitch, - rgb_buf, rgb_pitch, - yuvconstants, - pic_width, pic_height); - MOZ_ASSERT(!err); + if (yuv_color_space == YUVColorSpace::IDENTITY) { + // Special case for RGB image + GBRPlanarToARGB(src_y, y_pitch, src_u, uv_pitch, src_v, uv_pitch, + rgb_buf, rgb_pitch, pic_width, pic_height); + return; + } else { + DebugOnly err = libyuv::I444ToARGBMatrix(src_y, y_pitch, + src_u, uv_pitch, + src_v, uv_pitch, + rgb_buf, rgb_pitch, + yuvconstants, + pic_width, pic_height); + MOZ_ASSERT(!err); + } } else if (yuv_type == YV16) { const uint8* src_y = y_buf + y_pitch * pic_y + pic_x; const uint8* src_u = u_buf + uv_pitch * pic_y + pic_x / 2; @@ -301,6 +326,21 @@ void ScaleYCbCrToRGB32(const uint8* y_buf, return; } + if (yuv_type == YV24 && yuv_color_space == YUVColorSpace::IDENTITY) { + auto buffer = MakeUnique(source_width * source_height * 4); + auto buffer_pitch = source_width * 4; + GBRPlanarToARGB(y_buf, y_pitch, u_buf, uv_pitch, v_buf, uv_pitch, + buffer.get(), buffer_pitch, source_width, source_height); + DebugOnly err = + libyuv::ARGBScale(buffer.get(), buffer_pitch, + source_width, source_height, + rgb_buf, rgb_pitch, + width, height, + libyuv::kFilterBilinear); + MOZ_ASSERT(!err); + return; + } + DebugOnly err = libyuv::YUVToARGBScale(y_buf, y_pitch, u_buf, uv_pitch,