From 3e62b1fc9f641ee30b5b5b20374e8410d5ad2d6b Mon Sep 17 00:00:00 2001 From: u3shit Date: Fri, 24 Feb 2023 19:52:57 +0100 Subject: [PATCH] Issue #2118 - Part 2: Add support for Identity YUVColorSpace https://hg.mozilla.org/mozilla-central/rev/be342c90755d11551623362f2058c0326f63bbb3 --- 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 | 52 ++++++++++++++++--- 6 files changed, 97 insertions(+), 7 deletions(-) diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp index b5d21375e7..693b98c949 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 f06f6e08b1..ebc85c9e51 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.cpp +++ b/dom/media/platforms/agnostic/VPXDecoder.cpp @@ -158,6 +158,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 = VideoData::CreateAndCopyData(mInfo, mImageContainer, diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp index f9e8a2d268..12317ca6e4 100644 --- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp @@ -24,6 +24,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 @@ -54,6 +55,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; } @@ -353,7 +357,8 @@ FFmpegVideoDecoder::CreateImage(int64_t aOffset, int64_t aPts, 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 { @@ -369,6 +374,9 @@ FFmpegVideoDecoder::CreateImage(int64_t aOffset, int64_t aPts, case AVCOL_SPC_BT470BG: b.mYUVColorSpace = YUVColorSpace::BT601; break; + case AVCOL_SPC_RGB: + b.mYUVColorSpace = YUVColorSpace::IDENTITY; + break; default: break; } diff --git a/gfx/layers/ImageTypes.h b/gfx/layers/ImageTypes.h index 7a3b81f6e1..de154912b4 100644 --- a/gfx/layers/ImageTypes.h +++ b/gfx/layers/ImageTypes.h @@ -118,6 +118,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 499ae720e3..cad692a4d3 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -1091,6 +1091,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) @@ -1100,6 +1104,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 @@ -1108,6 +1113,8 @@ gfxUtils::Get4x3YuvColorMatrix(YUVColorSpace aYUVColorSpace) return rec601; case YUVColorSpace::BT709: return rec709; + case YUVColorSpace::IDENTITY: + return identity; default: MOZ_CRASH("Bad YUVColorSpace"); } @@ -1121,6 +1128,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 @@ -1129,6 +1137,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 78fd4ee89a..fae2c7df69 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 : MakeRange(pic_height)) { + for (const auto col : MakeRange(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, @@ -106,12 +124,19 @@ 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::I444ToARGB(src_y, y_pitch, - src_u, uv_pitch, - src_v, uv_pitch, - rgb_buf, rgb_pitch, - 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::I444ToARGB(src_y, y_pitch, + src_u, uv_pitch, + src_v, uv_pitch, + rgb_buf, rgb_pitch, + 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,