Add kIdentity_SkYUVColorSpace
This utility color space just maps Y to R, U to G and V to B when flattening or accessing the YUV planes. Clients can then add a colorFilter to directly manipulate the YUV values. This cannot land in Skia until the following CL lands in Chrome: https://chromium-review.googlesource.com/c/chromium/src/+/1506004 (Update usage of Skia's SkYUVColorSpace enum to allow the addition of a new value) Change-Id: Id9403ebbd009b45281d4d53fca52f68692d6c69f Reviewed-on: https://skia-review.googlesource.com/c/skia/+/198160 Reviewed-by: Jim Van Verth <jvanverth@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
e66a0b212a
commit
0a22ba84e0
@ -18,6 +18,17 @@
|
||||
#include "SkImage.h"
|
||||
#include "SkTo.h"
|
||||
|
||||
static sk_sp<SkColorFilter> yuv_to_rgb_colorfilter() {
|
||||
static const float kJPEGConversionMatrix[20] = {
|
||||
1.0f, 0.0f, 1.402f, 0.0f, -180.0f,
|
||||
1.0f, -0.344136f, -0.714136f, 0.0f, 136.0f,
|
||||
1.0f, 1.772f, 0.0f, 0.0f, -227.6f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f, 0.0f
|
||||
};
|
||||
|
||||
return SkColorFilter::MakeMatrixFilterRowMajor255(kJPEGConversionMatrix);
|
||||
}
|
||||
|
||||
namespace skiagm {
|
||||
class ImageFromYUVTextures : public GpuGM {
|
||||
public:
|
||||
@ -31,7 +42,7 @@ protected:
|
||||
}
|
||||
|
||||
SkISize onISize() override {
|
||||
return SkISize::Make(50, 300);
|
||||
return SkISize::Make(kBmpSize + 2 * kPad, 390);
|
||||
}
|
||||
|
||||
void onOnceBeforeDraw() override {
|
||||
@ -61,8 +72,8 @@ protected:
|
||||
uvPixels[0] = static_cast<signed char*>(fYUVBmps[1].getPixels());
|
||||
uvPixels[1] = static_cast<signed char*>(fYUVBmps[2].getPixels());
|
||||
|
||||
// Here we encode using the NTC encoding (even though we will draw it with all the supported
|
||||
// yuv color spaces when converted back to RGB)
|
||||
// Here we encode using the kJPEG_SkYUVColorSpace (i.e., full-swing Rec 601) even though
|
||||
// we will draw it with all the supported yuv color spaces when converted back to RGB
|
||||
for (int i = 0; i < kBmpSize * kBmpSize; ++i) {
|
||||
yPixels[i] = static_cast<unsigned char>(0.299f * SkGetPackedR32(rgbColors[i]) +
|
||||
0.587f * SkGetPackedG32(rgbColors[i]) +
|
||||
@ -145,45 +156,51 @@ protected:
|
||||
}
|
||||
|
||||
void onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas) override {
|
||||
constexpr SkScalar kPad = 10.f;
|
||||
// draw the original
|
||||
SkScalar yOffset = kPad;
|
||||
canvas->drawImage(fRGBImage.get(), kPad, yOffset);
|
||||
yOffset += kBmpSize + kPad;
|
||||
|
||||
SkTArray<sk_sp<SkImage>> images;
|
||||
images.push_back(fRGBImage);
|
||||
for (int space = kJPEG_SkYUVColorSpace; space <= kLastEnum_SkYUVColorSpace; ++space) {
|
||||
GrBackendTexture yuvTextures[3];
|
||||
this->createYUVTextures(context, yuvTextures);
|
||||
images.push_back(SkImage::MakeFromYUVTexturesCopy(context,
|
||||
static_cast<SkYUVColorSpace>(space),
|
||||
yuvTextures,
|
||||
kTopLeft_GrSurfaceOrigin));
|
||||
auto image = SkImage::MakeFromYUVTexturesCopy(context,
|
||||
static_cast<SkYUVColorSpace>(space),
|
||||
yuvTextures,
|
||||
kTopLeft_GrSurfaceOrigin);
|
||||
this->deleteBackendTextures(context, yuvTextures, 3);
|
||||
}
|
||||
for (int i = 0; i < images.count(); ++ i) {
|
||||
SkScalar y = (i + 1) * kPad + i * fYUVBmps[0].height();
|
||||
SkScalar x = kPad;
|
||||
|
||||
canvas->drawImage(images[i].get(), x, y);
|
||||
SkPaint paint;
|
||||
if (kIdentity_SkYUVColorSpace == space) {
|
||||
// The identity color space needs post-processing to appear correct
|
||||
paint.setColorFilter(yuv_to_rgb_colorfilter());
|
||||
}
|
||||
|
||||
canvas->drawImage(image.get(), kPad, yOffset, &paint);
|
||||
yOffset += kBmpSize + kPad;
|
||||
}
|
||||
|
||||
sk_sp<SkImage> image;
|
||||
for (int space = kJPEG_SkYUVColorSpace, i = images.count();
|
||||
space <= kLastEnum_SkYUVColorSpace; ++space, ++i) {
|
||||
for (int space = kJPEG_SkYUVColorSpace; space <= kLastEnum_SkYUVColorSpace; ++space) {
|
||||
GrBackendTexture yuvTextures[3];
|
||||
GrBackendTexture resultTexture;
|
||||
this->createYUVTextures(context, yuvTextures);
|
||||
this->createResultTexture(
|
||||
context, yuvTextures[0].width(), yuvTextures[0].height(), &resultTexture);
|
||||
image = SkImage::MakeFromYUVTexturesCopyWithExternalBackend(
|
||||
context,
|
||||
static_cast<SkYUVColorSpace>(space),
|
||||
yuvTextures,
|
||||
kTopLeft_GrSurfaceOrigin,
|
||||
resultTexture);
|
||||
auto image = SkImage::MakeFromYUVTexturesCopyWithExternalBackend(
|
||||
context,
|
||||
static_cast<SkYUVColorSpace>(space),
|
||||
yuvTextures,
|
||||
kTopLeft_GrSurfaceOrigin,
|
||||
resultTexture);
|
||||
|
||||
SkScalar y = (i + 1) * kPad + i * fYUVBmps[0].height();
|
||||
SkScalar x = kPad;
|
||||
SkPaint paint;
|
||||
if (kIdentity_SkYUVColorSpace == space) {
|
||||
// The identity color space needs post-processing to appear correct
|
||||
paint.setColorFilter(yuv_to_rgb_colorfilter());
|
||||
}
|
||||
canvas->drawImage(image.get(), kPad, yOffset, &paint);
|
||||
yOffset += kBmpSize + kPad;
|
||||
|
||||
canvas->drawImage(image.get(), x, y);
|
||||
GrBackendTexture texturesToDelete[4]{
|
||||
yuvTextures[0],
|
||||
yuvTextures[1],
|
||||
@ -198,7 +215,8 @@ private:
|
||||
sk_sp<SkImage> fRGBImage;
|
||||
SkBitmap fYUVBmps[3];
|
||||
|
||||
static constexpr int kBmpSize = 32;
|
||||
static constexpr SkScalar kPad = 10.0f;
|
||||
static constexpr int kBmpSize = 32;
|
||||
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
@ -276,6 +276,11 @@ static SkPMColor convert_yuva_to_rgba_709(uint8_t y, uint8_t u, uint8_t v, uint8
|
||||
}
|
||||
|
||||
static void extract_planes(const SkBitmap& bm, SkYUVColorSpace yuvColorSpace, PlaneData* planes) {
|
||||
if (kIdentity_SkYUVColorSpace == yuvColorSpace) {
|
||||
// To test the identity color space we use JPEG YUV planes
|
||||
yuvColorSpace = kJPEG_SkYUVColorSpace;
|
||||
}
|
||||
|
||||
SkASSERT(!(bm.width() % 2));
|
||||
SkASSERT(!(bm.height() % 2));
|
||||
|
||||
@ -561,6 +566,9 @@ protected:
|
||||
case kRec709_SkYUVColorSpace:
|
||||
*fFlattened.getAddr32(x, y) = convert_yuva_to_rgba_709(Y, U, V, A);
|
||||
break;
|
||||
case kIdentity_SkYUVColorSpace:
|
||||
*fFlattened.getAddr32(x, y) = SkPremultiplyARGBInline(A, Y, U, V);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -619,7 +627,7 @@ static sk_sp<SkImage> make_yuv_gen_image(const SkImageInfo& ii,
|
||||
}
|
||||
|
||||
static void draw_col_label(SkCanvas* canvas, int x, int yuvColorSpace, bool opaque) {
|
||||
static const char* kYUVColorSpaceNames[] = { "JPEG", "601", "709" };
|
||||
static const char* kYUVColorSpaceNames[] = { "JPEG", "601", "709", "Identity" };
|
||||
GR_STATIC_ASSERT(SK_ARRAY_COUNT(kYUVColorSpaceNames) == kLastEnum_SkYUVColorSpace+1);
|
||||
|
||||
SkPaint paint;
|
||||
@ -706,6 +714,17 @@ static GrBackendTexture create_yuva_texture(GrGpu* gpu, const SkBitmap& bm,
|
||||
return tex;
|
||||
}
|
||||
|
||||
static sk_sp<SkColorFilter> yuv_to_rgb_colorfilter() {
|
||||
static const float kJPEGConversionMatrix[20] = {
|
||||
1.0f, 0.0f, 1.402f, 0.0f, -180.0f,
|
||||
1.0f, -0.344136f, -0.714136f, 0.0f, 136.0f,
|
||||
1.0f, 1.772f, 0.0f, 0.0f, -227.6f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f, 0.0f
|
||||
};
|
||||
|
||||
return SkColorFilter::MakeMatrixFilterRowMajor255(kJPEGConversionMatrix);
|
||||
}
|
||||
|
||||
namespace skiagm {
|
||||
|
||||
// This GM creates an opaque and transparent bitmap, extracts the planes and then recombines
|
||||
@ -852,6 +871,12 @@ protected:
|
||||
|
||||
int x = kLabelWidth;
|
||||
for (int cs = kJPEG_SkYUVColorSpace; cs <= kLastEnum_SkYUVColorSpace; ++cs) {
|
||||
SkPaint paint;
|
||||
if (kIdentity_SkYUVColorSpace == cs) {
|
||||
// The identity color space needs post processing to appear correctly
|
||||
paint.setColorFilter(yuv_to_rgb_colorfilter());
|
||||
}
|
||||
|
||||
for (int opaque : { 0, 1 }) {
|
||||
int y = kLabelHeight;
|
||||
|
||||
@ -863,11 +888,14 @@ protected:
|
||||
for (int format = kAYUV_YUVFormat; format <= kLast_YUVFormat; ++format) {
|
||||
draw_row_label(canvas, y, format);
|
||||
if (fUseTargetColorSpace && fImages[opaque][cs][format]) {
|
||||
// Making a CS-specific version of a kIdentity_SkYUVColorSpace YUV image
|
||||
// doesn't make a whole lot of sense. The colorSpace conversion will
|
||||
// operate on the YUV components rather than the RGB components.
|
||||
sk_sp<SkImage> csImage =
|
||||
fImages[opaque][cs][format]->makeColorSpace(fTargetColorSpace);
|
||||
canvas->drawImage(csImage, x, y);
|
||||
canvas->drawImage(csImage, x, y, &paint);
|
||||
} else {
|
||||
canvas->drawImage(fImages[opaque][cs][format], x, y);
|
||||
canvas->drawImage(fImages[opaque][cs][format], x, y, &paint);
|
||||
}
|
||||
y += kTileWidthHeight + kPad;
|
||||
}
|
||||
|
@ -41,7 +41,8 @@ protected:
|
||||
}
|
||||
|
||||
SkISize onISize() override {
|
||||
return SkISize::Make(238, 120);
|
||||
int numRows = kLastEnum_SkYUVColorSpace + 1;
|
||||
return SkISize::Make(238, kDrawPad + numRows * kColorSpaceOffset);
|
||||
}
|
||||
|
||||
void onOnceBeforeDraw() override {
|
||||
@ -86,10 +87,6 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
constexpr SkScalar kDrawPad = 10.f;
|
||||
constexpr SkScalar kTestPad = 10.f;
|
||||
constexpr SkScalar kColorSpaceOffset = 36.f;
|
||||
|
||||
for (int space = kJPEG_SkYUVColorSpace; space <= kLastEnum_SkYUVColorSpace; ++space) {
|
||||
SkRect renderRect = SkRect::MakeWH(SkIntToScalar(fImage[0]->width()),
|
||||
SkIntToScalar(fImage[0]->height()));
|
||||
@ -132,6 +129,10 @@ protected:
|
||||
private:
|
||||
sk_sp<SkImage> fImage[3];
|
||||
|
||||
static constexpr SkScalar kDrawPad = 10.f;
|
||||
static constexpr SkScalar kTestPad = 10.f;
|
||||
static constexpr SkScalar kColorSpaceOffset = 36.f;
|
||||
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
||||
@ -151,7 +152,8 @@ protected:
|
||||
}
|
||||
|
||||
SkISize onISize() override {
|
||||
return SkISize::Make(48, 120);
|
||||
int numRows = kLastEnum_SkYUVColorSpace + 1;
|
||||
return SkISize::Make(48, kDrawPad + numRows * kColorSpaceOffset);
|
||||
}
|
||||
|
||||
void onOnceBeforeDraw() override {
|
||||
@ -211,10 +213,6 @@ protected:
|
||||
{ -1, SkColorChannel::kA }
|
||||
};
|
||||
|
||||
constexpr SkScalar kDrawPad = 10.f;
|
||||
constexpr SkScalar kTestPad = 10.f;
|
||||
constexpr SkScalar kColorSpaceOffset = 36.f;
|
||||
|
||||
for (int space = kJPEG_SkYUVColorSpace; space <= kLastEnum_SkYUVColorSpace; ++space) {
|
||||
SkRect renderRect = SkRect::MakeWH(SkIntToScalar(fImage[0]->width()),
|
||||
SkIntToScalar(fImage[0]->height()));
|
||||
@ -243,6 +241,10 @@ protected:
|
||||
private:
|
||||
sk_sp<SkImage> fImage[2];
|
||||
|
||||
static constexpr SkScalar kDrawPad = 10.f;
|
||||
static constexpr SkScalar kTestPad = 10.f;
|
||||
static constexpr SkScalar kColorSpaceOffset = 36.f;
|
||||
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
||||
|
@ -359,7 +359,7 @@ public:
|
||||
@param context GPU context
|
||||
@param yuvColorSpace How the YUV values are converted to RGB. One of:
|
||||
kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace,
|
||||
kRec709_SkYUVColorSpace
|
||||
kRec709_SkYUVColorSpace, kIdentity_SkYUVColorSpace
|
||||
@param yuvaTextures array of (up to four) YUVA textures on GPU which contain the,
|
||||
possibly interleaved, YUVA planes
|
||||
@param yuvaIndices array indicating which texture in yuvaTextures, and channel
|
||||
@ -384,7 +384,7 @@ public:
|
||||
@param context GPU context
|
||||
@param yuvColorSpace How the YUV values are converted to RGB. One of:
|
||||
kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace,
|
||||
kRec709_SkYUVColorSpace
|
||||
kRec709_SkYUVColorSpace, kIdentity_SkYUVColorSpace
|
||||
@param yuvaTextures array of (up to four) YUVA textures on GPU which contain the,
|
||||
possibly interleaved, YUVA planes
|
||||
@param yuvaIndices array indicating which texture in yuvaTextures, and channel
|
||||
@ -412,7 +412,7 @@ public:
|
||||
@param context GPU context
|
||||
@param yuvColorSpace How the YUV values are converted to RGB. One of:
|
||||
kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace,
|
||||
kRec709_SkYUVColorSpace
|
||||
kRec709_SkYUVColorSpace, kIdentity_SkYUVColorSpace
|
||||
@param yuvaTextures array of (up to four) YUVA textures on GPU which contain the,
|
||||
possibly interleaved, YUVA planes
|
||||
@param yuvaIndices array indicating which texture in yuvaTextures, and channel
|
||||
@ -444,7 +444,7 @@ public:
|
||||
@param context GPU context
|
||||
@param yuvColorSpace How the YUV values are converted to RGB. One of:
|
||||
kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace,
|
||||
kRec709_SkYUVColorSpace
|
||||
kRec709_SkYUVColorSpace, kIdentity_SkYUVColorSpace
|
||||
@param yuvaPixmaps array of (up to four) SkPixmap which contain the,
|
||||
possibly interleaved, YUVA planes
|
||||
@param yuvaIndices array indicating which pixmap in yuvaPixmaps, and channel
|
||||
@ -486,7 +486,7 @@ public:
|
||||
|
||||
@param context GPU context
|
||||
@param yuvColorSpace one of: kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace,
|
||||
kRec709_SkYUVColorSpace
|
||||
kRec709_SkYUVColorSpace, kIdentity_SkYUVColorSpace
|
||||
@param nv12Textures array of YUV textures on GPU
|
||||
@param imageOrigin one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin
|
||||
@param imageColorSpace range of colors; may be nullptr
|
||||
@ -507,7 +507,7 @@ public:
|
||||
|
||||
@param context GPU context
|
||||
@param yuvColorSpace one of: kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace,
|
||||
kRec709_SkYUVColorSpace
|
||||
kRec709_SkYUVColorSpace, kIdentity_SkYUVColorSpace
|
||||
@param nv12Textures array of YUV textures on GPU
|
||||
@param imageOrigin one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin
|
||||
@param backendTexture the resource that stores the final pixels
|
||||
|
@ -172,12 +172,17 @@ SK_API bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alph
|
||||
JPEG YUV values encode the full range of 0 to 255 for all three components.
|
||||
Video YUV values range from 16 to 235 for all three components. Details of
|
||||
encoding and conversion to RGB are described in YCbCr color space.
|
||||
|
||||
The identity colorspace exists to provide a utility mapping from Y to R, U to G and V to B.
|
||||
It can be used to visualize the YUV planes or to explicitly post process the YUV channels.
|
||||
*/
|
||||
enum SkYUVColorSpace {
|
||||
kJPEG_SkYUVColorSpace, //!< describes full range
|
||||
kRec601_SkYUVColorSpace, //!< describes SDTV range
|
||||
kRec709_SkYUVColorSpace, //!< describes HDTV range
|
||||
kLastEnum_SkYUVColorSpace = kRec709_SkYUVColorSpace, //!< last valid value
|
||||
kIdentity_SkYUVColorSpace, //!< maps Y->R, U->G, V->B
|
||||
|
||||
kLastEnum_SkYUVColorSpace = kIdentity_SkYUVColorSpace, //!< last valid value
|
||||
};
|
||||
|
||||
/** \struct SkImageInfo
|
||||
|
@ -28,6 +28,13 @@ static const float kRec709ConversionMatrix[16] = {
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
static const float kIdentityConversionMatrix[16] = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(const sk_sp<GrTextureProxy> proxies[],
|
||||
const SkYUVAIndex yuvaIndices[4],
|
||||
SkYUVColorSpace yuvColorSpace,
|
||||
@ -61,6 +68,9 @@ std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(const sk_sp<GrTextur
|
||||
case kRec709_SkYUVColorSpace:
|
||||
mat.setColMajorf(kRec709ConversionMatrix);
|
||||
break;
|
||||
case kIdentity_SkYUVColorSpace:
|
||||
mat.setColMajorf(kIdentityConversionMatrix);
|
||||
break;
|
||||
}
|
||||
return std::unique_ptr<GrFragmentProcessor>(new GrYUVtoRGBEffect(
|
||||
proxies, scales, filterModes, numPlanes, yuvaIndices, mat));
|
||||
|
Loading…
Reference in New Issue
Block a user