diff options
author | u3shit <u3shit@gmail.com> | 2023-02-24 22:25:38 +0100 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2023-02-26 19:41:47 +0100 |
commit | e736dc2d343a790deaaa9c8ea0bf9aa612db39f8 (patch) | |
tree | 525b73ea1f00bd89c873d885f2ef199100d26dcb /gfx | |
parent | 8ed007c4e8d44eda1710141efe14008caa5c027d (diff) | |
download | uxp-e736dc2d343a790deaaa9c8ea0bf9aa612db39f8.tar.gz |
Issue #2101 - Part 4: Add color range support to gfx/ycbcr
Loosely based on current mozilla code
https://hg.mozilla.org/mozilla-central/file/25a8668d92431d469b443f0f2030328bab754aea/gfx/ycbcr/yuv_convert.cpp
Diffstat (limited to 'gfx')
-rw-r--r-- | gfx/layers/ImageContainer.h | 3 | ||||
-rw-r--r-- | gfx/ycbcr/YCbCrUtils.cpp | 4 | ||||
-rw-r--r-- | gfx/ycbcr/scale_yuv_argb.cpp | 86 | ||||
-rw-r--r-- | gfx/ycbcr/scale_yuv_argb.h | 6 | ||||
-rw-r--r-- | gfx/ycbcr/yuv_convert.cpp | 103 | ||||
-rw-r--r-- | gfx/ycbcr/yuv_convert.h | 4 |
6 files changed, 128 insertions, 78 deletions
diff --git a/gfx/layers/ImageContainer.h b/gfx/layers/ImageContainer.h index 73085ba906..f3e88665fb 100644 --- a/gfx/layers/ImageContainer.h +++ b/gfx/layers/ImageContainer.h @@ -672,6 +672,7 @@ struct PlanarYCbCrData { gfx::IntSize mPicSize; StereoMode mStereoMode; YUVColorSpace mYUVColorSpace; + ColorRange mColorRange; gfx::IntRect GetPictureRect() const { return gfx::IntRect(mPicX, mPicY, @@ -684,7 +685,7 @@ struct PlanarYCbCrData { , mCbChannel(nullptr), mCrChannel(nullptr) , mCbCrStride(0), mCbCrSize(0, 0) , mCbSkip(0), mCrSkip(0) , mPicX(0), mPicY(0), mPicSize(0, 0), mStereoMode(StereoMode::MONO) - , mYUVColorSpace(YUVColorSpace::BT601) + , mYUVColorSpace(YUVColorSpace::BT601), mColorRange(ColorRange::LIMITED) {} }; diff --git a/gfx/ycbcr/YCbCrUtils.cpp b/gfx/ycbcr/YCbCrUtils.cpp index 8821978574..f5a4353e2f 100644 --- a/gfx/ycbcr/YCbCrUtils.cpp +++ b/gfx/ycbcr/YCbCrUtils.cpp @@ -119,6 +119,7 @@ ConvertYCbCrToRGB(const layers::PlanarYCbCrData& aData, aStride, yuvtype, aData.mYUVColorSpace, + aData.mColorRange, FILTER_BILINEAR); } else { // no prescale #if defined(HAVE_YCBCR_TO_RGB565) @@ -149,7 +150,8 @@ ConvertYCbCrToRGB(const layers::PlanarYCbCrData& aData, aData.mCbCrStride, aStride, yuvtype, - aData.mYUVColorSpace); + aData.mYUVColorSpace, + aData.mColorRange); } } diff --git a/gfx/ycbcr/scale_yuv_argb.cpp b/gfx/ycbcr/scale_yuv_argb.cpp index f102557010..4bf7ec5a97 100644 --- a/gfx/ycbcr/scale_yuv_argb.cpp +++ b/gfx/ycbcr/scale_yuv_argb.cpp @@ -21,12 +21,32 @@ #include "libyuv/row.h" #include "libyuv/scale_row.h" #include "libyuv/video_common.h" +#include "mozilla/Assertions.h" #ifdef __cplusplus namespace libyuv { extern "C" { #endif +const YuvConstants* GetYUVConstants(mozilla::YUVColorSpace yuv_color_space, + mozilla::ColorRange color_range) +{ + switch (yuv_color_space) { + case mozilla::YUVColorSpace::BT709: + return color_range == mozilla::ColorRange::LIMITED + ? &libyuv::kYuvH709Constants + : &libyuv::kYuvF709Constants; + + default: + MOZ_FALLTHROUGH_ASSERT("Unsupported YUVColorSpace"); + case mozilla::YUVColorSpace::BT601: + return color_range == mozilla::ColorRange::LIMITED + ? &libyuv::kYuvI601Constants + : &libyuv::kYuvJPEGConstants; + } +} + + // YUV to RGB conversion and scaling functions were implemented by referencing // scale_argb.cc // @@ -207,17 +227,16 @@ static __inline void YUVBuferIter_ConvertToARGBRow(YUVBuferIter& iter, uint8_t* iter.YUVToARGBRow(iter.src_row_y, iter.src_row_u, iter.src_row_v, argb_row, iter.yuvconstants, iter.src_width); } -void YUVBuferIter_Init(YUVBuferIter& iter, uint32_t src_fourcc, mozilla::YUVColorSpace yuv_color_space) { +void YUVBuferIter_Init(YUVBuferIter& iter, + uint32_t src_fourcc, + mozilla::YUVColorSpace yuv_color_space, + mozilla::ColorRange color_range) { iter.src_fourcc = src_fourcc; iter.y_index = 0; iter.src_row_y = iter.src_y; iter.src_row_u = iter.src_u; iter.src_row_v = iter.src_v; - if (yuv_color_space == mozilla::YUVColorSpace::BT709) { - iter.yuvconstants = &kYuvH709Constants; - } else { - iter.yuvconstants = &kYuvI601Constants; - } + iter.yuvconstants = GetYUVConstants(yuv_color_space, color_range); if (src_fourcc == FOURCC_I444) { YUVBuferIter_InitI444(iter); @@ -251,7 +270,8 @@ static void ScaleYUVToARGBDown2(int src_width, int src_height, int x, int dx, int y, int dy, enum FilterMode filtering, uint32_t src_fourcc, - mozilla::YUVColorSpace yuv_color_space) { + mozilla::YUVColorSpace yuv_color_space, + mozilla::ColorRange color_range) { int j; // Allocate 2 rows of ARGB for source conversion. @@ -269,7 +289,7 @@ static void ScaleYUVToARGBDown2(int src_width, int src_height, iter.src_y = src_y; iter.src_u = src_u; iter.src_v = src_v; - YUVBuferIter_Init(iter, src_fourcc, yuv_color_space); + YUVBuferIter_Init(iter, src_fourcc, yuv_color_space, color_range); void (*ScaleARGBRowDown2)(const uint8_t* src_argb, ptrdiff_t src_stride, uint8_t* dst_argb, int dst_width) = @@ -388,7 +408,8 @@ static void ScaleYUVToARGBDownEven(int src_width, int src_height, int x, int dx, int y, int dy, enum FilterMode filtering, uint32_t src_fourcc, - mozilla::YUVColorSpace yuv_color_space) { + mozilla::YUVColorSpace yuv_color_space, + mozilla::ColorRange color_range) { int j; // Allocate 2 rows of ARGB for source conversion. const int kRowSize = (src_width * 4 + 15) & ~15; @@ -435,7 +456,7 @@ static void ScaleYUVToARGBDownEven(int src_width, int src_height, iter.src_y = src_y; iter.src_u = src_u; iter.src_v = src_v; - YUVBuferIter_Init(iter, src_fourcc, yuv_color_space); + YUVBuferIter_Init(iter, src_fourcc, yuv_color_space, color_range); const int dyi = dy >> 16; int lastyi = yi; @@ -509,7 +530,8 @@ static void ScaleYUVToARGBBilinearDown(int src_width, int src_height, int x, int dx, int y, int dy, enum FilterMode filtering, uint32_t src_fourcc, - mozilla::YUVColorSpace yuv_color_space) { + mozilla::YUVColorSpace yuv_color_space, + mozilla::ColorRange color_range) { int j; void (*InterpolateRow)(uint8_t* dst_argb, const uint8_t* src_argb, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = @@ -595,7 +617,7 @@ static void ScaleYUVToARGBBilinearDown(int src_width, int src_height, iter.src_y = src_y; iter.src_u = src_u; iter.src_v = src_v; - YUVBuferIter_Init(iter, src_fourcc, yuv_color_space); + YUVBuferIter_Init(iter, src_fourcc, yuv_color_space, color_range); iter.MoveTo(iter, yi); // TODO(fbarchard): Consider not allocating row buffer for kFilterLinear. @@ -678,7 +700,8 @@ static void ScaleYUVToARGBBilinearUp(int src_width, int src_height, int x, int dx, int y, int dy, enum FilterMode filtering, uint32_t src_fourcc, - mozilla::YUVColorSpace yuv_color_space) { + mozilla::YUVColorSpace yuv_color_space, + mozilla::ColorRange color_range) { int j; void (*InterpolateRow)(uint8_t* dst_argb, const uint8_t* src_argb, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = @@ -775,7 +798,7 @@ static void ScaleYUVToARGBBilinearUp(int src_width, int src_height, iter.src_y = src_y; iter.src_u = src_u; iter.src_v = src_v; - YUVBuferIter_Init(iter, src_fourcc, yuv_color_space); + YUVBuferIter_Init(iter, src_fourcc, yuv_color_space, color_range); iter.MoveTo(iter, yi); // Allocate 2 rows of ARGB. @@ -862,7 +885,8 @@ static void ScaleYUVToARGBSimple(int src_width, int src_height, uint8_t* dst_argb, int x, int dx, int y, int dy, uint32_t src_fourcc, - mozilla::YUVColorSpace yuv_color_space) { + mozilla::YUVColorSpace yuv_color_space, + mozilla::ColorRange color_range) { int j; void (*ScaleARGBCols)(uint8_t* dst_argb, const uint8_t* src_argb, int dst_width, int x, int dx) = @@ -904,7 +928,7 @@ static void ScaleYUVToARGBSimple(int src_width, int src_height, iter.src_y = src_y; iter.src_u = src_u; iter.src_v = src_v; - YUVBuferIter_Init(iter, src_fourcc, yuv_color_space); + YUVBuferIter_Init(iter, src_fourcc, yuv_color_space, color_range); iter.MoveTo(iter, yi); int lasty = yi; @@ -931,7 +955,8 @@ static void YUVToARGBCopy(const uint8_t* src_y, int src_stride_y, uint8_t* dst_argb, int dst_stride_argb, int dst_width, int dst_height, uint32_t src_fourcc, - mozilla::YUVColorSpace yuv_color_space) + mozilla::YUVColorSpace yuv_color_space, + mozilla::ColorRange color_range) { YUVBuferIter iter; iter.src_width = src_width; @@ -942,7 +967,7 @@ static void YUVToARGBCopy(const uint8_t* src_y, int src_stride_y, iter.src_y = src_y; iter.src_u = src_u; iter.src_v = src_v; - YUVBuferIter_Init(iter, src_fourcc, yuv_color_space); + YUVBuferIter_Init(iter, src_fourcc, yuv_color_space, color_range); for (int j = 0; j < dst_height; ++j) { YUVBuferIter_ConvertToARGBRow(iter, dst_argb); @@ -959,7 +984,8 @@ static void ScaleYUVToARGB(const uint8_t* src_y, int src_stride_y, int dst_width, int dst_height, enum FilterMode filtering, uint32_t src_fourcc, - mozilla::YUVColorSpace yuv_color_space) + mozilla::YUVColorSpace yuv_color_space, + mozilla::ColorRange color_range) { // Initial source x/y coordinate and step values as 16.16 fixed point. int x = 0; @@ -996,7 +1022,8 @@ static void ScaleYUVToARGB(const uint8_t* src_y, int src_stride_y, x, dx, y, dy, filtering, src_fourcc, - yuv_color_space); + yuv_color_space, + color_range); return; } ScaleYUVToARGBDownEven(src_width, src_height, @@ -1012,7 +1039,8 @@ static void ScaleYUVToARGB(const uint8_t* src_y, int src_stride_y, x, dx, y, dy, filtering, src_fourcc, - yuv_color_space); + yuv_color_space, + color_range); return; } // Optimized odd scale down. ie 3, 5, 7, 9x. @@ -1027,7 +1055,8 @@ static void ScaleYUVToARGB(const uint8_t* src_y, int src_stride_y, dst_argb, dst_stride_argb, dst_width, dst_height, src_fourcc, - yuv_color_space); + yuv_color_space, + color_range); return; } } @@ -1047,7 +1076,8 @@ static void ScaleYUVToARGB(const uint8_t* src_y, int src_stride_y, x, dx, y, dy, filtering, src_fourcc, - yuv_color_space); + yuv_color_space, + color_range); return; } if (filtering) { @@ -1064,7 +1094,8 @@ static void ScaleYUVToARGB(const uint8_t* src_y, int src_stride_y, x, dx, y, dy, filtering, src_fourcc, - yuv_color_space); + yuv_color_space, + color_range); return; } ScaleYUVToARGBSimple(src_width, src_height, @@ -1079,7 +1110,8 @@ static void ScaleYUVToARGB(const uint8_t* src_y, int src_stride_y, dst_argb, x, dx, y, dy, src_fourcc, - yuv_color_space); + yuv_color_space, + color_range); } bool IsConvertSupported(uint32_t src_fourcc) @@ -1098,6 +1130,7 @@ int YUVToARGBScale(const uint8_t* src_y, int src_stride_y, const uint8_t* src_v, int src_stride_v, uint32_t src_fourcc, mozilla::YUVColorSpace yuv_color_space, + mozilla::ColorRange color_range, int src_width, int src_height, uint8_t* dst_argb, int dst_stride_argb, int dst_width, int dst_height, @@ -1119,7 +1152,8 @@ int YUVToARGBScale(const uint8_t* src_y, int src_stride_y, dst_width, dst_height, filtering, src_fourcc, - yuv_color_space); + yuv_color_space, + color_range); return 0; } diff --git a/gfx/ycbcr/scale_yuv_argb.h b/gfx/ycbcr/scale_yuv_argb.h index 25b7db04b5..aa526742c7 100644 --- a/gfx/ycbcr/scale_yuv_argb.h +++ b/gfx/ycbcr/scale_yuv_argb.h @@ -12,6 +12,7 @@ #define INCLUDE_LIBYUV_SCALE_YUV_ARGB_H_ #include "libyuv/basic_types.h" +#include "libyuv/row.h" // For YuvConstants #include "libyuv/scale.h" // For FilterMode #include "ImageTypes.h" // For YUVColorSpace @@ -21,11 +22,16 @@ namespace libyuv { extern "C" { #endif +const YuvConstants* GetYUVConstants(mozilla::YUVColorSpace yuv_color_space, + mozilla::ColorRange color_range); + + int YUVToARGBScale(const uint8_t* src_y, int src_stride_y, const uint8_t* src_u, int src_stride_u, const uint8_t* src_v, int src_stride_v, uint32_t src_fourcc, mozilla::YUVColorSpace yuv_color_space, + mozilla::ColorRange color_range, int src_width, int src_height, uint8_t* dst_argb, int dst_stride_argb, int dst_width, int dst_height, diff --git a/gfx/ycbcr/yuv_convert.cpp b/gfx/ycbcr/yuv_convert.cpp index e695509288..d3a8c53312 100644 --- a/gfx/ycbcr/yuv_convert.cpp +++ b/gfx/ycbcr/yuv_convert.cpp @@ -94,7 +94,8 @@ void ConvertYCbCrToRGB32(const uint8_t* y_buf, int uv_pitch, int rgb_pitch, YUVType yuv_type, - YUVColorSpace yuv_color_space) { + YUVColorSpace yuv_color_space, + ColorRange color_range) { // Deprecated function's conversion is accurate. @@ -107,7 +108,8 @@ void ConvertYCbCrToRGB32(const uint8_t* y_buf, // See Bug 1256475. bool use_deprecated = gfxPrefs::YCbCrAccurateConversion() || (supports_mmx() && supports_sse() && !supports_sse3() && - yuv_color_space == YUVColorSpace::BT601); + yuv_color_space == YUVColorSpace::BT601 && + color_range == ColorRange::LIMITED); // The deprecated function only support BT601. // See Bug 1210357. if (yuv_color_space != YUVColorSpace::BT601) { @@ -120,55 +122,53 @@ void ConvertYCbCrToRGB32(const uint8_t* y_buf, return; } - if (yuv_type == YV24) { - const uint8_t* src_y = y_buf + y_pitch * pic_y + pic_x; - const uint8_t* src_u = u_buf + uv_pitch * pic_y + pic_x; - const uint8_t* src_v = v_buf + uv_pitch * pic_y + pic_x; - 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<int> 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); + decltype(libyuv::I420ToARGBMatrix)* fConvertYUVToARGB = nullptr; + const uint8_t* src_y = nullptr; + const uint8_t* src_u = nullptr; + const uint8_t* src_v = nullptr; + + switch (yuv_type) { + case YV24: { + src_y = y_buf + y_pitch * pic_y + pic_x; + src_u = u_buf + uv_pitch * pic_y + pic_x; + src_v = v_buf + uv_pitch * pic_y + pic_x; + + 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; + } + + fConvertYUVToARGB = libyuv::I444ToARGBMatrix; + break; } - } else if (yuv_type == YV16) { - const uint8_t* src_y = y_buf + y_pitch * pic_y + pic_x; - const uint8_t* src_u = u_buf + uv_pitch * pic_y + pic_x / 2; - const uint8_t* src_v = v_buf + uv_pitch * pic_y + pic_x / 2; - DebugOnly<int> err = libyuv::I422ToARGB(src_y, y_pitch, - src_u, uv_pitch, - src_v, uv_pitch, - rgb_buf, rgb_pitch, - pic_width, pic_height); - MOZ_ASSERT(!err); - } else { - MOZ_ASSERT(yuv_type == YV12); - const uint8_t* src_y = y_buf + y_pitch * pic_y + pic_x; - const uint8_t* src_u = u_buf + (uv_pitch * pic_y + pic_x) / 2; - const uint8_t* src_v = v_buf + (uv_pitch * pic_y + pic_x) / 2; - if (yuv_color_space == YUVColorSpace::BT709) { - DebugOnly<int> err = libyuv::H420ToARGB(src_y, y_pitch, - src_u, uv_pitch, - src_v, uv_pitch, - rgb_buf, rgb_pitch, - pic_width, pic_height); - MOZ_ASSERT(!err); - } else { - MOZ_ASSERT(yuv_color_space == YUVColorSpace::BT601); - DebugOnly<int> err = libyuv::I420ToARGB(src_y, y_pitch, - src_u, uv_pitch, - src_v, uv_pitch, - rgb_buf, rgb_pitch, - pic_width, pic_height); - MOZ_ASSERT(!err); + case YV16: { + src_y = y_buf + y_pitch * pic_y + pic_x; + src_u = u_buf + uv_pitch * pic_y + pic_x / 2; + src_v = v_buf + uv_pitch * pic_y + pic_x / 2; + + fConvertYUVToARGB = libyuv::I422ToARGBMatrix; + break; } + case YV12: { + src_y = y_buf + y_pitch * pic_y + pic_x; + src_u = u_buf + (uv_pitch * pic_y + pic_x) / 2; + src_v = v_buf + (uv_pitch * pic_y + pic_x) / 2; + + fConvertYUVToARGB = libyuv::I420ToARGBMatrix; + break; + } + default: + MOZ_ASSERT_UNREACHABLE("Unsupported YUV type"); } + + auto yuv_constant = libyuv::GetYUVConstants(yuv_color_space, color_range); + + DebugOnly<int> err = + fConvertYUVToARGB(src_y, y_pitch, src_u, uv_pitch, src_v, uv_pitch, + rgb_buf, rgb_pitch, yuv_constant, pic_width, pic_height); + MOZ_ASSERT(!err); } // Convert a frame of YUV to 32 bit ARGB. @@ -300,6 +300,7 @@ void ScaleYCbCrToRGB32(const uint8_t* y_buf, int rgb_pitch, YUVType yuv_type, YUVColorSpace yuv_color_space, + ColorRange color_range, ScaleFilter filter) { bool use_deprecated = gfxPrefs::YCbCrAccurateConversion() || @@ -307,7 +308,8 @@ void ScaleYCbCrToRGB32(const uint8_t* y_buf, // libyuv does not support SIMD scaling on win 64bit. See Bug 1295927. supports_sse3() || #endif - (supports_mmx() && supports_sse() && !supports_sse3()); + (supports_mmx() && supports_sse() && !supports_sse3() && + color_range == ColorRange::LIMITED); // The deprecated function only support BT601. // See Bug 1210357. if (yuv_color_space != YUVColorSpace::BT601) { @@ -327,6 +329,8 @@ void ScaleYCbCrToRGB32(const uint8_t* y_buf, } if (yuv_type == YV24 && yuv_color_space == YUVColorSpace::IDENTITY) { + MOZ_ASSERT(color_range == ColorRange::LIMITED, + "Identity (aka RGB) with limited color range is unsupporeted"); auto buffer = MakeUnique<uint8_t[]>(source_width * source_height * 4); auto buffer_pitch = source_width * 4; GBRPlanarToARGB(y_buf, y_pitch, u_buf, uv_pitch, v_buf, uv_pitch, @@ -347,6 +351,7 @@ void ScaleYCbCrToRGB32(const uint8_t* y_buf, v_buf, uv_pitch, FourCCFromYUVType(yuv_type), yuv_color_space, + color_range, source_width, source_height, rgb_buf, rgb_pitch, width, height, diff --git a/gfx/ycbcr/yuv_convert.h b/gfx/ycbcr/yuv_convert.h index 8563b567ca..108e14b679 100644 --- a/gfx/ycbcr/yuv_convert.h +++ b/gfx/ycbcr/yuv_convert.h @@ -57,7 +57,8 @@ void ConvertYCbCrToRGB32(const uint8_t* yplane, int uvstride, int rgbstride, YUVType yuv_type, - YUVColorSpace yuv_color_space); + YUVColorSpace yuv_color_space, + ColorRange color_range); void ConvertYCbCrToRGB32_deprecated(const uint8_t* yplane, const uint8_t* uplane, @@ -87,6 +88,7 @@ void ScaleYCbCrToRGB32(const uint8_t* yplane, int rgbstride, YUVType yuv_type, YUVColorSpace yuv_color_space, + ColorRange color_range, ScaleFilter filter); void ScaleYCbCrToRGB32_deprecated(const uint8_t* yplane, |