Split SkYUVAInfo::PlanarConfig into PlaneConfig and Subsampling enums

Sometimes it's helpful to think about subsampling separately from
how the channels are spread across planes.

Bug: skia:10632
Change-Id: Ib03f71195f9706ef6def418b1f2125c29e0cf738
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/334102
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Brian Salomon 2020-11-11 16:34:19 -05:00 committed by Skia Commit-Bot
parent 70eba23828
commit e4387382c2
15 changed files with 456 additions and 251 deletions

View File

@ -7,6 +7,10 @@ This file includes a list of high level updates for each milestone release.
Milestone 88 Milestone 88
------------ ------------
* SkYUVAInfo now has separate enums for division of channels among planes and
the subsampling. The previous combined enum, PlanarConfig, is deprecated.
https://review.skia.org/334102
* Simplified SkDeferredDisplayListRecorder promise image API. Removed "release" * Simplified SkDeferredDisplayListRecorder promise image API. Removed "release"
callback and renamed "done" callback to "release". The new "release" proc can callback and renamed "done" callback to "release". The new "release" proc can
be null. Added a new SkYUVAInfo-based factory for YUVA promise texture images be null. Added a new SkYUVAInfo-based factory for YUVA promise texture images

View File

@ -166,7 +166,10 @@ static sk_sp<SkImage> make_yuv_420(GrRecordingContext* rContext,
int const strides[], int const strides[],
SkYUVColorSpace yuvSpace, SkYUVColorSpace yuvSpace,
sk_sp<SkColorSpace> cs) { sk_sp<SkColorSpace> cs) {
SkYUVAInfo yuvaInfo({w, h}, SkYUVAInfo::PlanarConfig::kY_U_V_420, yuvSpace); SkYUVAInfo yuvaInfo({w, h},
SkYUVAInfo::PlaneConfig::kY_U_V,
SkYUVAInfo::Subsampling::k420,
yuvSpace);
SkPixmap pixmaps[3]; SkPixmap pixmaps[3];
pixmaps[0].reset(SkImageInfo::MakeA8(w, h), data[0], strides[0]); pixmaps[0].reset(SkImageInfo::MakeA8(w, h), data[0], strides[0]);
w = (w + 1)/2; w = (w + 1)/2;

View File

@ -94,7 +94,10 @@ static sk_sp<SkImage> do_read_and_scale_yuv(Src* src,
if (!asyncContext.fResult) { if (!asyncContext.fResult) {
return nullptr; return nullptr;
} }
SkYUVAInfo yuvaInfo(size, SkYUVAInfo::PlanarConfig::kY_U_V_420, yuvCS); SkYUVAInfo yuvaInfo(size,
SkYUVAInfo::PlaneConfig::kY_U_V,
SkYUVAInfo::Subsampling::k420,
yuvCS);
SkPixmap yuvPMs[] = { SkPixmap yuvPMs[] = {
{yII, asyncContext.fResult->data(0), asyncContext.fResult->rowBytes(0)}, {yII, asyncContext.fResult->data(0), asyncContext.fResult->rowBytes(0)},
{uvII, asyncContext.fResult->data(1), asyncContext.fResult->rowBytes(1)}, {uvII, asyncContext.fResult->data(1), asyncContext.fResult->rowBytes(1)},

View File

@ -61,7 +61,8 @@ protected:
bmp = copy; bmp = copy;
} }
SkYUVAPixmapInfo pixmapInfo({bmp.dimensions(), SkYUVAPixmapInfo pixmapInfo({bmp.dimensions(),
SkYUVAInfo::PlanarConfig::kY_U_V_A_4204, SkYUVAInfo::PlaneConfig::kY_U_V_A,
SkYUVAInfo::Subsampling::k420,
kJPEG_Full_SkYUVColorSpace}, kJPEG_Full_SkYUVColorSpace},
SkYUVAPixmapInfo::DataType::kUnorm8, SkYUVAPixmapInfo::DataType::kUnorm8,
nullptr); nullptr);

View File

@ -123,51 +123,63 @@ public:
case kP016F_YUVFormat: case kP016F_YUVFormat:
case kNV12_YUVFormat: case kNV12_YUVFormat:
if (opaque) { if (opaque) {
fPlanarConfig = SkYUVAInfo::PlanarConfig::kY_UV_420; fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_UV;
fSubsampling = SkYUVAInfo::Subsampling::k420;
} else { } else {
fPlanarConfig = SkYUVAInfo::PlanarConfig::kY_UV_A_4204; fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_UV_A;
fSubsampling = SkYUVAInfo::Subsampling::k420;
} }
break; break;
case kY416_YUVFormat: case kY416_YUVFormat:
case kY410_YUVFormat: case kY410_YUVFormat:
if (opaque) { if (opaque) {
fPlanarConfig = SkYUVAInfo::PlanarConfig::kUYV_444; fPlaneConfig = SkYUVAInfo::PlaneConfig::kUYV;
fSubsampling = SkYUVAInfo::Subsampling::k444;
} else { } else {
fPlanarConfig = SkYUVAInfo::PlanarConfig::kUYVA_4444; fPlaneConfig = SkYUVAInfo::PlaneConfig::kUYVA;
fSubsampling = SkYUVAInfo::Subsampling::k444;
} }
break; break;
case kAYUV_YUVFormat: case kAYUV_YUVFormat:
if (opaque) { if (opaque) {
fPlanarConfig = SkYUVAInfo::PlanarConfig::kYUV_444; fPlaneConfig = SkYUVAInfo::PlaneConfig::kYUV;
fSubsampling = SkYUVAInfo::Subsampling::k444;
} else { } else {
fPlanarConfig = SkYUVAInfo::PlanarConfig::kYUVA_4444; fPlaneConfig = SkYUVAInfo::PlaneConfig::kYUVA;
fSubsampling = SkYUVAInfo::Subsampling::k444;
} }
break; break;
case kNV21_YUVFormat: case kNV21_YUVFormat:
if (opaque) { if (opaque) {
fPlanarConfig = SkYUVAInfo::PlanarConfig::kY_VU_420; fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_VU;
fSubsampling = SkYUVAInfo::Subsampling::k420;
} else { } else {
fPlanarConfig = SkYUVAInfo::PlanarConfig::kY_VU_A_4204; fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_VU_A;
fSubsampling = SkYUVAInfo::Subsampling::k420;
} }
break; break;
case kI420_YUVFormat: case kI420_YUVFormat:
if (opaque) { if (opaque) {
fPlanarConfig = SkYUVAInfo::PlanarConfig::kY_U_V_420; fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_U_V;
fSubsampling = SkYUVAInfo::Subsampling::k420;
} else { } else {
fPlanarConfig = SkYUVAInfo::PlanarConfig::kY_U_V_A_4204; fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_U_V_A;
fSubsampling = SkYUVAInfo::Subsampling::k420;
} }
break; break;
case kYV12_YUVFormat: case kYV12_YUVFormat:
if (opaque) { if (opaque) {
fPlanarConfig = SkYUVAInfo::PlanarConfig::kY_V_U_420; fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_V_U;
fSubsampling = SkYUVAInfo::Subsampling::k420;
} else { } else {
fPlanarConfig = SkYUVAInfo::PlanarConfig::kY_V_U_A_4204; fPlaneConfig = SkYUVAInfo::PlaneConfig::kY_V_U_A;
fSubsampling = SkYUVAInfo::Subsampling::k420;
} }
break; break;
} }
} }
int numPlanes() const { return SkYUVAInfo::NumPlanes(fPlanarConfig); } int numPlanes() const { return SkYUVAInfo::NumPlanes(fPlaneConfig); }
SkYUVAPixmaps makeYUVAPixmaps(SkISize dimensions, SkYUVAPixmaps makeYUVAPixmaps(SkISize dimensions,
SkYUVColorSpace yuvColorSpace, SkYUVColorSpace yuvColorSpace,
@ -175,14 +187,15 @@ public:
int numBitmaps) const; int numBitmaps) const;
private: private:
SkYUVAInfo::PlanarConfig fPlanarConfig; SkYUVAInfo::PlaneConfig fPlaneConfig;
SkYUVAInfo::Subsampling fSubsampling;
}; };
SkYUVAPixmaps YUVAPlanarConfig::makeYUVAPixmaps(SkISize dimensions, SkYUVAPixmaps YUVAPlanarConfig::makeYUVAPixmaps(SkISize dimensions,
SkYUVColorSpace yuvColorSpace, SkYUVColorSpace yuvColorSpace,
const SkBitmap bitmaps[], const SkBitmap bitmaps[],
int numBitmaps) const { int numBitmaps) const {
SkYUVAInfo info(dimensions, fPlanarConfig, yuvColorSpace); SkYUVAInfo info(dimensions, fPlaneConfig, fSubsampling, yuvColorSpace);
SkPixmap pmaps[SkYUVAInfo::kMaxPlanes]; SkPixmap pmaps[SkYUVAInfo::kMaxPlanes];
int n = info.numPlanes(); int n = info.numPlanes();
if (numBitmaps < n) { if (numBitmaps < n) {
@ -1198,7 +1211,10 @@ protected:
for (auto cs : {kRec709_SkYUVColorSpace, kRec601_SkYUVColorSpace, kJPEG_SkYUVColorSpace, for (auto cs : {kRec709_SkYUVColorSpace, kRec601_SkYUVColorSpace, kJPEG_SkYUVColorSpace,
kBT2020_SkYUVColorSpace}) { kBT2020_SkYUVColorSpace}) {
split_into_yuv(fOrig.get(), cs, fPM); split_into_yuv(fOrig.get(), cs, fPM);
SkYUVAInfo yuvaInfo(fOrig->dimensions(), SkYUVAInfo::PlanarConfig::kY_U_V_444, cs); SkYUVAInfo yuvaInfo(fOrig->dimensions(),
SkYUVAInfo::PlaneConfig::kY_U_V,
SkYUVAInfo::Subsampling::k444,
cs);
auto yuvaPixmaps = SkYUVAPixmaps::FromExternalPixmaps(yuvaInfo, fPM); auto yuvaPixmaps = SkYUVAPixmaps::FromExternalPixmaps(yuvaInfo, fPM);
auto img = SkImage::MakeFromYUVAPixmaps(canvas->recordingContext(), auto img = SkImage::MakeFromYUVAPixmaps(canvas->recordingContext(),
yuvaPixmaps, yuvaPixmaps,

View File

@ -13,6 +13,8 @@
#include "include/core/SkSize.h" #include "include/core/SkSize.h"
#include "include/core/SkYUVAIndex.h" #include "include/core/SkYUVAIndex.h"
#include <tuple>
/** /**
* Specifies the structure of planes for a YUV image with optional alpha. The actual planar data * Specifies the structure of planes for a YUV image with optional alpha. The actual planar data
* is not part of this structure and depending on usage is in external textures or pixmaps. * is not part of this structure and depending on usage is in external textures or pixmaps.
@ -20,6 +22,59 @@
class SK_API SkYUVAInfo { class SK_API SkYUVAInfo {
public: public:
/** /**
* Specifies how YUV (and optionally A) are divided among planes. Planes are separated by
* underscores in the enum value names. Within each plane the pixmap/texture channels are
* mapped to the YUVA channels in the order specified, e.g. for kY_UV Y is in channel 0 of plane
* 0, U is in channel 0 of plane 1, and V is in channel 1 of plane 1. Channel ordering
* within a pixmap/texture given the channels it contains:
* A: 0:A
* Luminance/Gray: 0:Gray
* RG 0:R, 1:G
* RGB 0:R, 1:G, 2:B
* RGBA 0:R, 1:G, 2:B, 3:A
*/
enum class PlaneConfig {
kUnknown,
kY_U_V, ///< Plane 0: Y, Plane 1: U, Plane 2: V
kY_V_U, ///< Plane 0: Y, Plane 1: V, Plane 2: U
kY_UV, ///< Plane 0: Y, Plane 1: UV
kY_VU, ///< Plane 0: Y, Plane 1: VU
kYUV, ///< Plane 0: YUV
kUYV, ///< Plane 0: UYV
kY_U_V_A, ///< Plane 0: Y, Plane 1: U, Plane 2: V, Plane 3: A
kY_V_U_A, ///< Plane 0: Y, Plane 1: V, Plane 2: U, Plane 3: A
kY_UV_A, ///< Plane 0: Y, Plane 1: UV, Plane 2: A
kY_VU_A, ///< Plane 0: Y, Plane 1: VU, Plane 2: A
kYUVA, ///< Plane 0: YUVA
kUYVA, ///< Plane 0: UYVA
kLast = kUYVA
};
/**
* UV subsampling is also specified in the enum value names using J:a:b notation (e.g. 4:2:0 is
* 1/2 horizontal and 1/2 vertical resolution for U and V). If alpha is present it is not sub-
* sampled. Note that Subsampling values other than k444 are only valid with PlaneConfig values
* that have U and V in different planes than Y (and A, if present).
*/
enum class Subsampling {
kUnknown,
k444, ///< No subsampling. UV values for each Y.
k422, ///< 1 set of UV values for each 2x1 block of Y values.
k420, ///< 1 set of UV values for each 2x2 block of Y values.
k440, ///< 1 set of UV values for each 1x2 block of Y values.
k411, ///< 1 set of UV values for each 4x1 block of Y values.
k410, ///< 1 set of UV values for each 4x2 block of Y values.
kLast = k410
};
/**
* Deprecated in favor of separate PlaneConfig and Subsampling enums.
*
* Specifies how YUV (and optionally A) are divided among planes. Planes are separated by * Specifies how YUV (and optionally A) are divided among planes. Planes are separated by
* underscores in the enum value names. Within each plane the pixmap/texture channels are * underscores in the enum value names. Within each plane the pixmap/texture channels are
* mapped to the YUVA channels in the order specified, e.g. for kY_UV Y is in channel 0 of plane * mapped to the YUVA channels in the order specified, e.g. for kY_UV Y is in channel 0 of plane
@ -34,9 +89,6 @@ public:
* UV subsampling is also specified in the enum value names using J:a:b notation (e.g. 4:2:0 is * UV subsampling is also specified in the enum value names using J:a:b notation (e.g. 4:2:0 is
* 1/2 horizontal and 1/2 vertical resolution for U and V). A fourth number is added if alpha * 1/2 horizontal and 1/2 vertical resolution for U and V). A fourth number is added if alpha
* is present (always 4 as only full resolution alpha is supported). * is present (always 4 as only full resolution alpha is supported).
*
* Currently this only has three-plane formats but more will be added as usage and testing of
* this expands.
*/ */
enum class PlanarConfig { enum class PlanarConfig {
kUnknown, kUnknown,
@ -65,6 +117,9 @@ public:
kUYVA_4444, ///< Plane 0: UYVA kUYVA_4444, ///< Plane 0: UYVA
}; };
static constexpr std::tuple<PlaneConfig, Subsampling>
PlanarConfigToPlaneConfigAndSubsampling(PlanarConfig);
/** /**
* Describes how subsampled chroma values are sited relative to luma values. * Describes how subsampled chroma values are sited relative to luma values.
* *
@ -80,37 +135,39 @@ public:
static constexpr int kMaxPlanes = 4; static constexpr int kMaxPlanes = 4;
/** /**
* Given image dimensions, a planar configuration, and origin, determine the expected size of * Given image dimensions, a planer configuration, subsampling, and origin, determine the
* each plane. Returns the number of expected planes. planeDimensions[0] through * expected size of each plane. Returns the number of expected planes. planeDimensions[0]
* planeDimensons[<ret>] are written. The input image dimensions are as displayed (after the * through planeDimensions[<ret>] are written. The input image dimensions are as displayed
* planes have been transformed to the intended display orientation). The plane dimensions * (after the planes have been transformed to the intended display orientation). The plane
* are output as stored in memory. * dimensions are output as the planes are stored in memory (may be rotated from image
* dimensions).
*/ */
static int PlaneDimensions(SkISize imageDimensions, static int PlaneDimensions(SkISize imageDimensions,
PlanarConfig, PlaneConfig,
Subsampling ,
SkEncodedOrigin, SkEncodedOrigin,
SkISize planeDimensions[kMaxPlanes]); SkISize planeDimensions[kMaxPlanes]);
/** Number of planes for a given PlanarConfig. */ /** Number of planes for a given PlaneConfig. */
static constexpr int NumPlanes(PlanarConfig); static constexpr int NumPlanes(PlaneConfig);
/** /**
* Number of Y, U, V, A channels in the ith plane for a given PlanarConfig (or 0 if i is * Number of Y, U, V, A channels in the ith plane for a given PlaneConfig (or 0 if i is
* invalid). * invalid).
*/ */
static constexpr int NumChannelsInPlane(PlanarConfig, int i); static constexpr int NumChannelsInPlane(PlaneConfig, int i);
/** /**
* Given a PlanarConfig and a set of channel flags for each plane, convert to SkYUVAIndex * Given a PlaneConfig and a set of channel flags for each plane, convert to SkYUVAIndex
* representation. Fails if channel flags aren't valid for the PlanarConfig (i.e. don't have * representation. Fails if channel flags aren't valid for the PlaneConfig (i.e. don't have
* enough channels in a plane). * enough channels in a plane).
*/ */
static bool GetYUVAIndices(PlanarConfig, static bool GetYUVAIndices(PlaneConfig,
const uint32_t planeChannelFlags[kMaxPlanes], const uint32_t planeChannelFlags[kMaxPlanes],
SkYUVAIndex indices[SkYUVAIndex::kIndexCount]); SkYUVAIndex indices[SkYUVAIndex::kIndexCount]);
/** Does the PlanarConfig have alpha values? */ /** Does the PlaneConfig have alpha values? */
static bool HasAlpha(PlanarConfig); static bool HasAlpha(PlaneConfig);
SkYUVAInfo() = default; SkYUVAInfo() = default;
SkYUVAInfo(const SkYUVAInfo&) = default; SkYUVAInfo(const SkYUVAInfo&) = default;
@ -119,6 +176,20 @@ public:
* 'dimensions' should specify the size of the full resolution image (after planes have been * 'dimensions' should specify the size of the full resolution image (after planes have been
* oriented to how the image is displayed as indicated by 'origin'). * oriented to how the image is displayed as indicated by 'origin').
*/ */
SkYUVAInfo(SkISize dimensions,
PlaneConfig,
Subsampling,
SkYUVColorSpace,
SkEncodedOrigin origin = kTopLeft_SkEncodedOrigin,
Siting sitingX = Siting::kCentered,
Siting sitingY = Siting::kCentered);
/**
* Deprecated in favor of constructor that takes PlaneConfig and Subsampling.
*
* 'dimensions' should specify the size of the full resolution image (after planes have been
* oriented to how the image is displayed as indicated by 'origin').
*/
SkYUVAInfo(SkISize dimensions, SkYUVAInfo(SkISize dimensions,
PlanarConfig, PlanarConfig,
SkYUVColorSpace, SkYUVColorSpace,
@ -128,7 +199,14 @@ public:
SkYUVAInfo& operator=(const SkYUVAInfo& that) = default; SkYUVAInfo& operator=(const SkYUVAInfo& that) = default;
PlanarConfig planarConfig() const { return fPlanarConfig; } PlaneConfig planeConfig() const { return fPlaneConfig; }
Subsampling subsampling() const { return fSubsampling; }
/**
* Deprecated. May return kUnknown even if this is valid because not all valid PlaneConfig/
* Subsampling pairs have am equivalent PlanarConfig value.
*/
PlanarConfig planarConfig() const;
/** /**
* Dimensions of the full resolution image (after planes have been oriented to how the image * Dimensions of the full resolution image (after planes have been oriented to how the image
@ -144,7 +222,7 @@ public:
SkEncodedOrigin origin() const { return fOrigin; } SkEncodedOrigin origin() const { return fOrigin; }
bool hasAlpha() const { return HasAlpha(fPlanarConfig); } bool hasAlpha() const { return HasAlpha(fPlaneConfig); }
/** /**
* Returns the number of planes and initializes planeDimensions[0]..planeDimensions[<ret>] to * Returns the number of planes and initializes planeDimensions[0]..planeDimensions[<ret>] to
@ -152,7 +230,7 @@ public:
* transformation to image display space as indicated by origin(). * transformation to image display space as indicated by origin().
*/ */
int planeDimensions(SkISize planeDimensions[kMaxPlanes]) const { int planeDimensions(SkISize planeDimensions[kMaxPlanes]) const {
return PlaneDimensions(fDimensions, fPlanarConfig, fOrigin, planeDimensions); return PlaneDimensions(fDimensions, fPlaneConfig, fSubsampling, fOrigin, planeDimensions);
} }
/** /**
@ -163,28 +241,29 @@ public:
size_t computeTotalBytes(const size_t rowBytes[kMaxPlanes], size_t computeTotalBytes(const size_t rowBytes[kMaxPlanes],
size_t planeSizes[kMaxPlanes] = nullptr) const; size_t planeSizes[kMaxPlanes] = nullptr) const;
int numPlanes() const { return NumPlanes(fPlanarConfig); } int numPlanes() const { return NumPlanes(fPlaneConfig); }
int numChannelsInPlane(int i) const { return NumChannelsInPlane(fPlanarConfig, i); } int numChannelsInPlane(int i) const { return NumChannelsInPlane(fPlaneConfig, i); }
/** /**
* Given a set of channel flags for each plane, converts this->planarConfig() to SkYUVAIndex * Given a set of channel flags for each plane, converts this->planarConfig() to SkYUVAIndex
* representation. Fails if the channel flags aren't valid for the PlanarConfig (i.e. don't have * representation. Fails if the channel flags aren't valid for the PlaneConfig (i.e. don't have
* enough channels in a plane). * enough channels in a plane).
*/ */
bool toYUVAIndices(const uint32_t channelFlags[4], SkYUVAIndex indices[4]) const { bool toYUVAIndices(const uint32_t channelFlags[4], SkYUVAIndex indices[4]) const {
return GetYUVAIndices(fPlanarConfig, channelFlags, indices); return GetYUVAIndices(fPlaneConfig, channelFlags, indices);
} }
bool operator==(const SkYUVAInfo& that) const; bool operator==(const SkYUVAInfo& that) const;
bool operator!=(const SkYUVAInfo& that) const { return !(*this == that); } bool operator!=(const SkYUVAInfo& that) const { return !(*this == that); }
bool isValid() const { return fPlanarConfig != PlanarConfig::kUnknown; } bool isValid() const { return fPlaneConfig != PlaneConfig::kUnknown; }
private: private:
SkISize fDimensions = {0, 0}; SkISize fDimensions = {0, 0};
PlanarConfig fPlanarConfig = PlanarConfig::kUnknown; PlaneConfig fPlaneConfig = PlaneConfig::kUnknown;
Subsampling fSubsampling = Subsampling::kUnknown;
SkYUVColorSpace fYUVColorSpace = SkYUVColorSpace::kIdentity_SkYUVColorSpace; SkYUVColorSpace fYUVColorSpace = SkYUVColorSpace::kIdentity_SkYUVColorSpace;
@ -198,74 +277,87 @@ private:
Siting fSitingY = Siting::kCentered; Siting fSitingY = Siting::kCentered;
}; };
constexpr int SkYUVAInfo::NumPlanes(PlanarConfig planarConfig) { constexpr int SkYUVAInfo::NumPlanes(PlaneConfig planeConfig) {
switch (planarConfig) { switch (planeConfig) {
case PlanarConfig::kUnknown: return 0; case PlaneConfig::kUnknown: return 0;
case PlaneConfig::kY_U_V: return 3;
case PlanarConfig::kY_U_V_444: return 3; case PlaneConfig::kY_V_U: return 3;
case PlanarConfig::kY_U_V_422: return 3; case PlaneConfig::kY_UV: return 2;
case PlanarConfig::kY_U_V_420: return 3; case PlaneConfig::kY_VU: return 2;
case PlanarConfig::kY_V_U_420: return 3; case PlaneConfig::kYUV: return 1;
case PlanarConfig::kY_U_V_440: return 3; case PlaneConfig::kUYV: return 1;
case PlanarConfig::kY_U_V_411: return 3; case PlaneConfig::kY_U_V_A: return 4;
case PlanarConfig::kY_U_V_410: return 3; case PlaneConfig::kY_V_U_A: return 4;
case PlaneConfig::kY_UV_A: return 3;
case PlanarConfig::kY_U_V_A_4204: return 4; case PlaneConfig::kY_VU_A: return 3;
case PlanarConfig::kY_V_U_A_4204: return 4; case PlaneConfig::kYUVA: return 1;
case PlaneConfig::kUYVA: return 1;
case PlanarConfig::kY_UV_420: return 2;
case PlanarConfig::kY_VU_420: return 2;
case PlanarConfig::kY_UV_A_4204: return 3;
case PlanarConfig::kY_VU_A_4204: return 3;
case PlanarConfig::kYUV_444: return 1;
case PlanarConfig::kUYV_444: return 1;
case PlanarConfig::kYUVA_4444: return 1;
case PlanarConfig::kUYVA_4444: return 1;
} }
SkUNREACHABLE; SkUNREACHABLE;
} }
constexpr int SkYUVAInfo::NumChannelsInPlane(PlanarConfig config, int i) { constexpr int SkYUVAInfo::NumChannelsInPlane(PlaneConfig config, int i) {
switch (config) { switch (config) {
case PlanarConfig::kUnknown: case PlaneConfig::kUnknown:
return 0; return 0;
case SkYUVAInfo::PlanarConfig::kY_U_V_444: case SkYUVAInfo::PlaneConfig::kY_U_V:
case SkYUVAInfo::PlanarConfig::kY_U_V_422: case SkYUVAInfo::PlaneConfig::kY_V_U:
case SkYUVAInfo::PlanarConfig::kY_U_V_420:
case SkYUVAInfo::PlanarConfig::kY_V_U_420:
case SkYUVAInfo::PlanarConfig::kY_U_V_440:
case SkYUVAInfo::PlanarConfig::kY_U_V_411:
case SkYUVAInfo::PlanarConfig::kY_U_V_410:
return i >= 0 && i < 3 ? 1 : 0; return i >= 0 && i < 3 ? 1 : 0;
case SkYUVAInfo::PlanarConfig::kY_U_V_A_4204: case SkYUVAInfo::PlaneConfig::kY_UV:
case SkYUVAInfo::PlanarConfig::kY_V_U_A_4204: case SkYUVAInfo::PlaneConfig::kY_VU:
return i >= 0 && i < 4 ? 1 : 0;
case SkYUVAInfo::PlanarConfig::kY_UV_420:
case SkYUVAInfo::PlanarConfig::kY_VU_420:
switch (i) { switch (i) {
case 0: return 1; case 0: return 1;
case 1: return 2; case 1: return 2;
default: return 0; default: return 0;
} }
case SkYUVAInfo::PlanarConfig::kY_UV_A_4204: case SkYUVAInfo::PlaneConfig::kYUV:
case SkYUVAInfo::PlanarConfig::kY_VU_A_4204: case SkYUVAInfo::PlaneConfig::kUYV:
return i == 0 ? 3 : 0;
case SkYUVAInfo::PlaneConfig::kY_U_V_A:
case SkYUVAInfo::PlaneConfig::kY_V_U_A:
return i >= 0 && i < 4 ? 1 : 0;
case SkYUVAInfo::PlaneConfig::kY_UV_A:
case SkYUVAInfo::PlaneConfig::kY_VU_A:
switch (i) { switch (i) {
case 0: return 1; case 0: return 1;
case 1: return 2; case 1: return 2;
case 2: return 1; case 2: return 1;
default: return 0; default: return 0;
} }
case SkYUVAInfo::PlanarConfig::kYUV_444: case SkYUVAInfo::PlaneConfig::kYUVA:
case SkYUVAInfo::PlanarConfig::kUYV_444: case SkYUVAInfo::PlaneConfig::kUYVA:
return i == 0 ? 3 : 0;
case SkYUVAInfo::PlanarConfig::kYUVA_4444:
case SkYUVAInfo::PlanarConfig::kUYVA_4444:
return i == 0 ? 4 : 0; return i == 0 ? 4 : 0;
} }
return 0; return 0;
} }
constexpr std::tuple<SkYUVAInfo::PlaneConfig, SkYUVAInfo::Subsampling>
SkYUVAInfo::PlanarConfigToPlaneConfigAndSubsampling(PlanarConfig planarConfig) {
switch (planarConfig) {
case PlanarConfig::kUnknown:
return {PlaneConfig::kUnknown, Subsampling ::kUnknown};
case PlanarConfig::kY_U_V_444: return {PlaneConfig::kY_U_V, Subsampling::k444};
case PlanarConfig::kY_U_V_422: return {PlaneConfig::kY_U_V, Subsampling::k422};
case PlanarConfig::kY_U_V_420: return {PlaneConfig::kY_U_V, Subsampling::k420};
case PlanarConfig::kY_V_U_420: return {PlaneConfig::kY_V_U, Subsampling::k420};
case PlanarConfig::kY_U_V_440: return {PlaneConfig::kY_U_V, Subsampling::k440};
case PlanarConfig::kY_U_V_411: return {PlaneConfig::kY_U_V, Subsampling::k411};
case PlanarConfig::kY_U_V_410: return {PlaneConfig::kY_U_V, Subsampling::k410};
case PlanarConfig::kY_U_V_A_4204: return {PlaneConfig::kY_U_V_A, Subsampling::k420};
case PlanarConfig::kY_V_U_A_4204: return {PlaneConfig::kY_V_U_A, Subsampling::k420};
case PlanarConfig::kY_UV_420: return {PlaneConfig::kY_UV, Subsampling::k420};
case PlanarConfig::kY_VU_420: return {PlaneConfig::kY_VU, Subsampling::k420};
case PlanarConfig::kY_UV_A_4204: return {PlaneConfig::kY_UV_A, Subsampling::k420};
case PlanarConfig::kY_VU_A_4204: return {PlaneConfig::kY_VU_A, Subsampling::k420};
case PlanarConfig::kYUV_444: return {PlaneConfig::kYUV, Subsampling::k444};
case PlanarConfig::kUYV_444: return {PlaneConfig::kUYV, Subsampling::k444};
case PlanarConfig::kYUVA_4444: return {PlaneConfig::kYUVA, Subsampling::k444};
case PlanarConfig::kUYVA_4444: return {PlaneConfig::kUYVA, Subsampling::k444};
}
SkUNREACHABLE;
}
#endif #endif

View File

@ -29,6 +29,8 @@ class SK_API SkYUVAPixmapInfo {
public: public:
static constexpr auto kMaxPlanes = SkYUVAInfo::kMaxPlanes; static constexpr auto kMaxPlanes = SkYUVAInfo::kMaxPlanes;
using PlaneConfig = SkYUVAInfo::PlaneConfig;
using Subsampling = SkYUVAInfo::Subsampling;
using PlanarConfig = SkYUVAInfo::PlanarConfig; using PlanarConfig = SkYUVAInfo::PlanarConfig;
/** /**
@ -53,13 +55,16 @@ public:
/** Init based on texture formats supported by the context. */ /** Init based on texture formats supported by the context. */
SupportedDataTypes(const GrImageContext&); SupportedDataTypes(const GrImageContext&);
/** All legal combinations of PlanarConfig and DataType are supported. */ /** All legal combinations of PlaneConfig and DataType are supported. */
static constexpr SupportedDataTypes All(); static constexpr SupportedDataTypes All();
/** /**
* Checks whether there is a supported combination of color types for planes structured * Checks whether there is a supported combination of color types for planes structured
* as indicated by PlanarConfig with channel data types as indicated by DataType. * as indicated by PlaneConfig with channel data types as indicated by DataType.
*/ */
constexpr bool supported(PlaneConfig, DataType) const;
/** Deprecated. Use PlaneConfig version. */
constexpr bool supported(PlanarConfig, DataType) const; constexpr bool supported(PlanarConfig, DataType) const;
/** /**
@ -152,7 +157,7 @@ public:
* Returns true if this has been configured with a non-empty dimensioned SkYUVAInfo with * Returns true if this has been configured with a non-empty dimensioned SkYUVAInfo with
* compatible color types and row bytes. * compatible color types and row bytes.
*/ */
bool isValid() const { return fPlaneInfos[0].colorType() != kUnknown_SkColorType; } bool isValid() const { return fYUVAInfo.isValid(); }
/** Is this valid and does it use color types allowed by the passed SupportedDataTypes? */ /** Is this valid and does it use color types allowed by the passed SupportedDataTypes? */
bool isSupported(const SupportedDataTypes&) const; bool isSupported(const SupportedDataTypes&) const;
@ -281,7 +286,7 @@ constexpr SkYUVAPixmapInfo::SupportedDataTypes SkYUVAPixmapInfo::SupportedDataTy
return combinations; return combinations;
} }
constexpr bool SkYUVAPixmapInfo::SupportedDataTypes::supported(PlanarConfig config, constexpr bool SkYUVAPixmapInfo::SupportedDataTypes::supported(PlaneConfig config,
DataType type) const { DataType type) const {
int n = SkYUVAInfo::NumPlanes(config); int n = SkYUVAInfo::NumPlanes(config);
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
@ -295,6 +300,12 @@ constexpr bool SkYUVAPixmapInfo::SupportedDataTypes::supported(PlanarConfig conf
return true; return true;
} }
constexpr bool SkYUVAPixmapInfo::SupportedDataTypes::supported(PlanarConfig planarConfig,
DataType type) const {
auto pc = std::get<0>(SkYUVAInfo::PlanarConfigToPlaneConfigAndSubsampling(planarConfig));
return this->supported(pc, type);
}
constexpr SkColorType SkYUVAPixmapInfo::DefaultColorTypeForDataType(DataType dataType, constexpr SkColorType SkYUVAPixmapInfo::DefaultColorTypeForDataType(DataType dataType,
int numChannels) { int numChannels) {
switch (numChannels) { switch (numChannels) {

View File

@ -23,8 +23,6 @@ class SK_API GrYUVABackendTextureInfo {
public: public:
static constexpr auto kMaxPlanes = SkYUVAInfo::kMaxPlanes; static constexpr auto kMaxPlanes = SkYUVAInfo::kMaxPlanes;
using PlanarConfig = SkYUVAInfo::PlanarConfig;
/** Default GrYUVABackendTextureInfo is invalid. */ /** Default GrYUVABackendTextureInfo is invalid. */
GrYUVABackendTextureInfo() = default; GrYUVABackendTextureInfo() = default;

View File

@ -796,24 +796,25 @@ static bool is_yuv_supported(const jpeg_decompress_struct* dinfo,
SkASSERT(hSampY == dinfo->max_h_samp_factor); SkASSERT(hSampY == dinfo->max_h_samp_factor);
SkASSERT(vSampY == dinfo->max_v_samp_factor); SkASSERT(vSampY == dinfo->max_v_samp_factor);
SkYUVAInfo::PlanarConfig tempPlanarConfig; SkYUVAInfo::Subsampling tempSubsampling;
if (1 == hSampY && 1 == vSampY) { if (1 == hSampY && 1 == vSampY) {
tempPlanarConfig = SkYUVAInfo::PlanarConfig::kY_U_V_444; tempSubsampling = SkYUVAInfo::Subsampling::k444;
} else if (2 == hSampY && 1 == vSampY) { } else if (2 == hSampY && 1 == vSampY) {
tempPlanarConfig = SkYUVAInfo::PlanarConfig::kY_U_V_422; tempSubsampling = SkYUVAInfo::Subsampling::k422;
} else if (2 == hSampY && 2 == vSampY) { } else if (2 == hSampY && 2 == vSampY) {
tempPlanarConfig = SkYUVAInfo::PlanarConfig::kY_U_V_420; tempSubsampling = SkYUVAInfo::Subsampling::k420;
} else if (1 == hSampY && 2 == vSampY) { } else if (1 == hSampY && 2 == vSampY) {
tempPlanarConfig = SkYUVAInfo::PlanarConfig::kY_U_V_440; tempSubsampling = SkYUVAInfo::Subsampling::k440;
} else if (4 == hSampY && 1 == vSampY) { } else if (4 == hSampY && 1 == vSampY) {
tempPlanarConfig = SkYUVAInfo::PlanarConfig::kY_U_V_411; tempSubsampling = SkYUVAInfo::Subsampling::k411;
} else if (4 == hSampY && 2 == vSampY) { } else if (4 == hSampY && 2 == vSampY) {
tempPlanarConfig = SkYUVAInfo::PlanarConfig::kY_U_V_410; tempSubsampling = SkYUVAInfo::Subsampling::k410;
} else { } else {
return false; return false;
} }
if (supportedDataTypes && if (supportedDataTypes &&
!supportedDataTypes->supported(tempPlanarConfig, SkYUVAPixmapInfo::DataType::kUnorm8)) { !supportedDataTypes->supported(SkYUVAInfo::PlaneConfig::kY_U_V,
SkYUVAPixmapInfo::DataType::kUnorm8)) {
return false; return false;
} }
if (yuvaPixmapInfo) { if (yuvaPixmapInfo) {
@ -824,7 +825,8 @@ static bool is_yuv_supported(const jpeg_decompress_struct* dinfo,
rowBytes[i] = dinfo->comp_info[i].width_in_blocks * DCTSIZE; rowBytes[i] = dinfo->comp_info[i].width_in_blocks * DCTSIZE;
} }
SkYUVAInfo yuvaInfo(codec.dimensions(), SkYUVAInfo yuvaInfo(codec.dimensions(),
tempPlanarConfig, SkYUVAInfo::PlaneConfig::kY_U_V,
tempSubsampling,
kJPEG_Full_SkYUVColorSpace, kJPEG_Full_SkYUVColorSpace,
codec.getOrigin(), codec.getOrigin(),
SkYUVAInfo::Siting::kCentered, SkYUVAInfo::Siting::kCentered,

View File

@ -8,10 +8,31 @@
#include "include/core/SkYUVAInfo.h" #include "include/core/SkYUVAInfo.h"
#include "src/core/SkSafeMath.h" #include "src/core/SkSafeMath.h"
#include <algorithm>
static bool is_plane_config_compatible_with_subsampling(SkYUVAInfo::PlaneConfig config,
SkYUVAInfo::Subsampling subsampling) {
if (config == SkYUVAInfo::PlaneConfig::kUnknown ||
subsampling == SkYUVAInfo::Subsampling::kUnknown) {
return false;
}
return subsampling == SkYUVAInfo::Subsampling::k444 ||
(config != SkYUVAInfo::PlaneConfig::kYUV &&
config != SkYUVAInfo::PlaneConfig::kYUVA &&
config != SkYUVAInfo::PlaneConfig::kUYV &&
config != SkYUVAInfo::PlaneConfig::kUYVA);
}
int SkYUVAInfo::PlaneDimensions(SkISize imageDimensions, int SkYUVAInfo::PlaneDimensions(SkISize imageDimensions,
PlanarConfig planarConfig, PlaneConfig planeConfig,
Subsampling subsampling,
SkEncodedOrigin origin, SkEncodedOrigin origin,
SkISize planeDimensions[SkYUVAInfo::kMaxPlanes]) { SkISize planeDimensions[SkYUVAInfo::kMaxPlanes]) {
std::fill_n(planeDimensions, SkYUVAInfo::kMaxPlanes, SkISize{0, 0});
if (!is_plane_config_compatible_with_subsampling(planeConfig, subsampling)) {
return 0;
}
int w = imageDimensions.width(); int w = imageDimensions.width();
int h = imageDimensions.height(); int h = imageDimensions.height();
if (origin >= kLeftTop_SkEncodedOrigin) { if (origin >= kLeftTop_SkEncodedOrigin) {
@ -20,66 +41,50 @@ int SkYUVAInfo::PlaneDimensions(SkISize imageDimensions,
} }
auto down2 = [](int x) { return (x + 1)/2; }; auto down2 = [](int x) { return (x + 1)/2; };
auto down4 = [](int x) { return (x + 3)/4; }; auto down4 = [](int x) { return (x + 3)/4; };
switch (planarConfig) { SkISize uvSize;
case PlanarConfig::kUnknown: switch (subsampling) {
planeDimensions[0] = case Subsampling::kUnknown: SkUNREACHABLE;
planeDimensions[1] =
planeDimensions[2] = case Subsampling::k444: uvSize = { w , h }; break;
planeDimensions[3] = {0, 0}; case Subsampling::k422: uvSize = {down2(w), h }; break;
return 0; case Subsampling::k420: uvSize = {down2(w), down2(h)}; break;
case PlanarConfig::kY_U_V_444: case Subsampling::k440: uvSize = { w , down2(h)}; break;
planeDimensions[0] = planeDimensions[1] = planeDimensions[2] = {w, h}; case Subsampling::k411: uvSize = {down4(w), h }; break;
planeDimensions[3] = {0, 0}; case Subsampling::k410: uvSize = {down4(w), down2(h)}; break;
return 3; }
case PlanarConfig::kY_U_V_422: switch (planeConfig) {
case PlaneConfig::kUnknown: SkUNREACHABLE;
case PlaneConfig::kY_U_V:
case PlaneConfig::kY_V_U:
planeDimensions[0] = {w, h}; planeDimensions[0] = {w, h};
planeDimensions[1] = planeDimensions[2] = {down2(w), h}; planeDimensions[1] = planeDimensions[2] = uvSize;
planeDimensions[3] = {0, 0};
return 3; return 3;
case PlanarConfig::kY_U_V_420:
case PlanarConfig::kY_V_U_420: case PlaneConfig::kY_UV:
case PlaneConfig::kY_VU:
planeDimensions[0] = {w, h}; planeDimensions[0] = {w, h};
planeDimensions[1] = planeDimensions[2] = {down2(w), down2(h)}; planeDimensions[1] = uvSize;
planeDimensions[3] = {0, 0};
return 3;
case PlanarConfig::kY_UV_A_4204:
case PlanarConfig::kY_VU_A_4204:
planeDimensions[0] = planeDimensions[2] = {w, h};
planeDimensions[1] = {down2(w), down2(h)};
planeDimensions[3] = {0, 0};
return 3;
case PlanarConfig::kY_U_V_440:
planeDimensions[0] = {w, h};
planeDimensions[1] = planeDimensions[2] = {w, down2(h)};
planeDimensions[3] = {0, 0};
return 3;
case PlanarConfig::kY_U_V_411:
planeDimensions[0] = {w, h};
planeDimensions[1] = planeDimensions[2] = {down4(w), h};
planeDimensions[3] = {0, 0};
return 3;
case PlanarConfig::kY_U_V_410:
planeDimensions[0] = {w, h};
planeDimensions[1] = planeDimensions[2] = {down4(w), down2(h)};
planeDimensions[3] = {0, 0};
return 3;
case PlanarConfig::kY_U_V_A_4204:
case PlanarConfig::kY_V_U_A_4204:
planeDimensions[0] = planeDimensions[3] = {w, h};
planeDimensions[1] = planeDimensions[2] = {down2(w), down2(h)};
return 4;
case PlanarConfig::kY_UV_420:
case PlanarConfig::kY_VU_420:
planeDimensions[0] = {w, h};
planeDimensions[1] = {down2(w), down2(h)};
planeDimensions[2] = planeDimensions[3] = {0, 0};
return 2; return 2;
case PlanarConfig::kYUV_444:
case PlanarConfig::kUYV_444: case PlaneConfig::kY_U_V_A:
case PlanarConfig::kYUVA_4444: case PlaneConfig::kY_V_U_A:
case PlanarConfig::kUYVA_4444: planeDimensions[0] = planeDimensions[3] = {w, h};
planeDimensions[1] = planeDimensions[2] = uvSize;
return 4;
case PlaneConfig::kY_UV_A:
case PlaneConfig::kY_VU_A:
planeDimensions[0] = planeDimensions[2] = {w, h};
planeDimensions[1] = uvSize;
return 3;
case PlaneConfig::kYUV:
case PlaneConfig::kUYV:
case PlaneConfig::kYUVA:
case PlaneConfig::kUYVA:
planeDimensions[0] = {w, h}; planeDimensions[0] = {w, h};
planeDimensions[1] = planeDimensions[2] = planeDimensions[3] = {0, 0}; SkASSERT(planeDimensions[0] == uvSize);
return 1; return 1;
} }
SkUNREACHABLE; SkUNREACHABLE;
@ -125,76 +130,71 @@ static bool channel_index_to_channel(uint32_t channelFlags,
} }
} }
bool SkYUVAInfo::GetYUVAIndices(PlanarConfig config, bool SkYUVAInfo::GetYUVAIndices(PlaneConfig config,
const uint32_t planeChannelFlags[kMaxPlanes], const uint32_t planeChannelFlags[kMaxPlanes],
SkYUVAIndex indices[SkYUVAIndex::kIndexCount]) { SkYUVAIndex indices[SkYUVAIndex::kIndexCount]) {
struct Location {int plane, chanIdx;}; struct Location {int plane, chanIdx;};
const Location* locations = nullptr; const Location* locations = nullptr;
switch (config) { switch (config) {
case PlanarConfig::kUnknown: case PlaneConfig::kUnknown:
return false; return false;
case PlanarConfig::kY_U_V_444: case PlaneConfig::kY_U_V: {
case PlanarConfig::kY_U_V_422:
case PlanarConfig::kY_U_V_420:
case PlanarConfig::kY_U_V_440:
case PlanarConfig::kY_U_V_411:
case PlanarConfig::kY_U_V_410: {
static constexpr Location kLocations[] = {{0, 0}, {1, 0}, {2, 0}, {-1, -1}}; static constexpr Location kLocations[] = {{0, 0}, {1, 0}, {2, 0}, {-1, -1}};
locations = kLocations; locations = kLocations;
break; break;
} }
case PlanarConfig::kY_V_U_420: { case PlaneConfig::kY_V_U: {
static constexpr Location kLocations[] = {{0, 0}, {2, 0}, {1, 0}, {-1, -1}}; static constexpr Location kLocations[] = {{0, 0}, {2, 0}, {1, 0}, {-1, -1}};
locations = kLocations; locations = kLocations;
break; break;
} }
case PlanarConfig::kY_U_V_A_4204: { case PlaneConfig::kY_UV: {
static constexpr Location kLocations[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}};
locations = kLocations;
break;
}
case PlanarConfig::kY_V_U_A_4204: {
static constexpr Location kLocations[] = {{0, 0}, {2, 0}, {1, 0}, {3, 0}};
locations = kLocations;
break;
}
case PlanarConfig::kY_UV_420: {
static constexpr Location kLocations[] = {{0, 0}, {1, 0}, {1, 1}, {-1, -1}}; static constexpr Location kLocations[] = {{0, 0}, {1, 0}, {1, 1}, {-1, -1}};
locations = kLocations; locations = kLocations;
break; break;
} }
case PlanarConfig::kY_VU_420: { case PlaneConfig::kY_VU: {
static constexpr Location kLocations[] = {{0, 0}, {1, 1}, {1, 0}, {-1, -1}}; static constexpr Location kLocations[] = {{0, 0}, {1, 1}, {1, 0}, {-1, -1}};
locations = kLocations; locations = kLocations;
break; break;
} }
case PlanarConfig::kY_UV_A_4204: { case PlaneConfig::kYUV: {
static constexpr Location kLocations[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}};
locations = kLocations;
break;
}
case PlanarConfig::kY_VU_A_4204: {
static constexpr Location kLocations[] = {{0, 0}, {1, 1}, {1, 0}, {2, 0}};
locations = kLocations;
break;
}
case PlanarConfig::kYUV_444: {
static constexpr Location kLocations[] = {{0, 0}, {0, 1}, {0, 2}, {-1, -1}}; static constexpr Location kLocations[] = {{0, 0}, {0, 1}, {0, 2}, {-1, -1}};
locations = kLocations; locations = kLocations;
break; break;
} }
case PlanarConfig::kUYV_444: { case PlaneConfig::kUYV: {
static constexpr Location kLocations[] = {{0, 1}, {0, 0}, {0, 2}, {-1, -1}}; static constexpr Location kLocations[] = {{0, 1}, {0, 0}, {0, 2}, {-1, -1}};
locations = kLocations; locations = kLocations;
break; break;
} }
case PlanarConfig::kYUVA_4444: { case PlaneConfig::kY_U_V_A: {
static constexpr Location kLocations[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}};
locations = kLocations;
break;
}
case PlaneConfig::kY_V_U_A: {
static constexpr Location kLocations[] = {{0, 0}, {2, 0}, {1, 0}, {3, 0}};
locations = kLocations;
break;
}
case PlaneConfig::kY_UV_A: {
static constexpr Location kLocations[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}};
locations = kLocations;
break;
}
case PlaneConfig::kY_VU_A: {
static constexpr Location kLocations[] = {{0, 0}, {1, 1}, {1, 0}, {2, 0}};
locations = kLocations;
break;
}
case PlaneConfig::kYUVA: {
static constexpr Location kLocations[] = {{0, 0}, {0, 1}, {0, 2}, {0, 3}}; static constexpr Location kLocations[] = {{0, 0}, {0, 1}, {0, 2}, {0, 3}};
locations = kLocations; locations = kLocations;
break; break;
} }
case PlanarConfig::kUYVA_4444: { case PlaneConfig::kUYVA: {
static constexpr Location kLocations[] = {{0, 1}, {0, 0}, {0, 2}, {0, 3}}; static constexpr Location kLocations[] = {{0, 1}, {0, 0}, {0, 2}, {0, 3}};
locations = kLocations; locations = kLocations;
break; break;
@ -217,56 +217,58 @@ bool SkYUVAInfo::GetYUVAIndices(PlanarConfig config,
return true; return true;
} }
bool SkYUVAInfo::HasAlpha(PlanarConfig planarConfig) { bool SkYUVAInfo::HasAlpha(PlaneConfig planeConfig) {
switch (planarConfig) { switch (planeConfig) {
case PlanarConfig::kUnknown: return false; case PlaneConfig::kUnknown: return false;
case PlanarConfig::kY_U_V_444: return false; case PlaneConfig::kY_U_V: return false;
case PlanarConfig::kY_U_V_422: return false; case PlaneConfig::kY_V_U: return false;
case PlanarConfig::kY_U_V_420: return false; case PlaneConfig::kY_UV: return false;
case PlanarConfig::kY_V_U_420: return false; case PlaneConfig::kY_VU: return false;
case PlanarConfig::kY_U_V_440: return false; case PlaneConfig::kYUV: return false;
case PlanarConfig::kY_U_V_411: return false; case PlaneConfig::kUYV: return false;
case PlanarConfig::kY_U_V_410: return false;
case PlanarConfig::kY_U_V_A_4204: return true; case PlaneConfig::kY_U_V_A: return true;
case PlanarConfig::kY_V_U_A_4204: return true; case PlaneConfig::kY_V_U_A: return true;
case PlaneConfig::kY_UV_A: return true;
case PlanarConfig::kY_UV_420: return false; case PlaneConfig::kY_VU_A: return true;
case PlanarConfig::kY_VU_420: return false; case PlaneConfig::kYUVA: return true;
case PlaneConfig::kUYVA: return true;
case PlanarConfig::kY_UV_A_4204: return true;
case PlanarConfig::kY_VU_A_4204: return true;
case PlanarConfig::kYUV_444: return false;
case PlanarConfig::kUYV_444: return false;
case PlanarConfig::kYUVA_4444: return true;
case PlanarConfig::kUYVA_4444: return true;
} }
SkUNREACHABLE; SkUNREACHABLE;
} }
SkYUVAInfo::SkYUVAInfo(SkISize dimensions,
PlaneConfig planeConfig,
Subsampling subsampling,
SkYUVColorSpace yuvColorSpace,
SkEncodedOrigin origin,
Siting sitingX,
Siting sitingY)
: fDimensions(dimensions)
, fPlaneConfig(planeConfig)
, fSubsampling(subsampling)
, fYUVColorSpace(yuvColorSpace)
, fOrigin(origin)
, fSitingX(sitingX)
, fSitingY(sitingY) {
if (fDimensions.isEmpty() ||
!is_plane_config_compatible_with_subsampling(planeConfig, subsampling)) {
*this = {};
SkASSERT(!this->isValid());
return;
}
SkASSERT(this->isValid());
}
SkYUVAInfo::SkYUVAInfo(SkISize dimensions, SkYUVAInfo::SkYUVAInfo(SkISize dimensions,
PlanarConfig planarConfig, PlanarConfig planarConfig,
SkYUVColorSpace yuvColorSpace, SkYUVColorSpace yuvColorSpace,
SkEncodedOrigin origin, SkEncodedOrigin origin,
Siting sitingX, Siting sitingX,
Siting sitingY) Siting sitingY) {
: fDimensions(dimensions) auto [c, s] = PlanarConfigToPlaneConfigAndSubsampling(planarConfig);
, fPlanarConfig(planarConfig) *this = SkYUVAInfo(dimensions, c, s, yuvColorSpace, origin, sitingX, sitingY);
, fYUVColorSpace(yuvColorSpace)
, fOrigin(origin)
, fSitingX(sitingX)
, fSitingY(sitingY) {
if (fDimensions.width() <= 0 ||
fDimensions.height() <= 0 ||
planarConfig == PlanarConfig::kUnknown) {
*this = {};
SkASSERT(!this->isValid());
return;
}
SkASSERT(this->isValid());
} }
size_t SkYUVAInfo::computeTotalBytes(const size_t rowBytes[kMaxPlanes], size_t SkYUVAInfo::computeTotalBytes(const size_t rowBytes[kMaxPlanes],
@ -302,8 +304,75 @@ size_t SkYUVAInfo::computeTotalBytes(const size_t rowBytes[kMaxPlanes],
return safe.ok() ? totalBytes : SIZE_MAX; return safe.ok() ? totalBytes : SIZE_MAX;
} }
SkYUVAInfo::PlanarConfig SkYUVAInfo::planarConfig() const {
SkASSERT(!this->isValid() || is_plane_config_compatible_with_subsampling(fPlaneConfig,
fSubsampling));
switch (fPlaneConfig) {
case PlaneConfig::kUnknown: return PlanarConfig::kUnknown;
case PlaneConfig::kY_U_V:
switch (fSubsampling) {
case Subsampling::kUnknown: SkUNREACHABLE;
case Subsampling::k444: return PlanarConfig::kY_U_V_444;
case Subsampling::k422: return PlanarConfig::kY_U_V_422;
case Subsampling::k420: return PlanarConfig::kY_U_V_420;
case Subsampling::k440: return PlanarConfig::kY_U_V_440;
case Subsampling::k411: return PlanarConfig::kY_U_V_411;
case Subsampling::k410: return PlanarConfig::kY_U_V_410;
}
SkUNREACHABLE;
case PlaneConfig::kY_V_U:
return fSubsampling == Subsampling::k420 ? PlanarConfig::kY_V_U_420
: PlanarConfig::kUnknown;
case PlaneConfig::kY_UV:
return fSubsampling == Subsampling::k420 ? PlanarConfig::kY_UV_420
: PlanarConfig::kUnknown;
case PlaneConfig::kY_VU:
return fSubsampling == Subsampling::k420 ? PlanarConfig::kY_VU_420
: PlanarConfig::kUnknown;
case PlaneConfig::kYUV:
SkASSERT(fSubsampling == Subsampling::k444);
return PlanarConfig::kYUV_444;
case PlaneConfig::kUYV:
SkASSERT(fSubsampling == Subsampling::k444);
return PlanarConfig::kUYV_444;
case PlaneConfig::kY_U_V_A:
return fSubsampling == Subsampling::k420 ? PlanarConfig::kY_U_V_A_4204
: PlanarConfig::kUnknown;
case PlaneConfig::kY_V_U_A:
return fSubsampling == Subsampling::k420 ? PlanarConfig::kY_V_U_A_4204
: PlanarConfig::kUnknown;
case PlaneConfig::kY_UV_A:
return fSubsampling == Subsampling::k420 ? PlanarConfig::kY_UV_A_4204
: PlanarConfig::kUnknown;
case PlaneConfig::kY_VU_A:
return fSubsampling == Subsampling::k420 ? PlanarConfig::kY_VU_A_4204
: PlanarConfig::kUnknown;
case PlaneConfig::kYUVA:
SkASSERT(fSubsampling == Subsampling::k444);
return PlanarConfig::kYUVA_4444;
case PlaneConfig::kUYVA:
SkASSERT(fSubsampling == Subsampling::k444);
return PlanarConfig::kUYVA_4444;
}
SkUNREACHABLE;
}
bool SkYUVAInfo::operator==(const SkYUVAInfo& that) const { bool SkYUVAInfo::operator==(const SkYUVAInfo& that) const {
return fPlanarConfig == that.fPlanarConfig && return fPlaneConfig == that.fPlaneConfig &&
fSubsampling == that.fSubsampling &&
fYUVColorSpace == that.fYUVColorSpace && fYUVColorSpace == that.fYUVColorSpace &&
fDimensions == that.fDimensions && fDimensions == that.fDimensions &&
fSitingX == that.fSitingX && fSitingX == that.fSitingX &&

View File

@ -172,7 +172,7 @@ bool SkYUVAPixmapInfo::isSupported(const SupportedDataTypes& supportedDataTypes)
if (!this->isValid()) { if (!this->isValid()) {
return false; return false;
} }
return supportedDataTypes.supported(fYUVAInfo.planarConfig(), fDataType); return supportedDataTypes.supported(fYUVAInfo.planeConfig(), fDataType);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////

View File

@ -67,7 +67,8 @@ DEF_TEST(ImageGenerator, reporter) {
// Check that the YUV decoding API does not cause any crashes // Check that the YUV decoding API does not cause any crashes
ig.queryYUVAInfo(SkYUVAPixmapInfo::SupportedDataTypes::All(), &yuvaPixmapInfo); ig.queryYUVAInfo(SkYUVAPixmapInfo::SupportedDataTypes::All(), &yuvaPixmapInfo);
SkYUVAInfo yuvaInfo({250, 250}, SkYUVAInfo yuvaInfo({250, 250},
SkYUVAInfo::PlanarConfig::kY_UV_420, SkYUVAInfo::PlaneConfig::kY_UV,
SkYUVAInfo::Subsampling::k420,
kJPEG_Full_SkYUVColorSpace); kJPEG_Full_SkYUVColorSpace);
yuvaPixmapInfo = SkYUVAPixmapInfo(yuvaInfo, yuvaPixmapInfo = SkYUVAPixmapInfo(yuvaInfo,
SkYUVAPixmapInfo::DataType::kUnorm8, SkYUVAPixmapInfo::DataType::kUnorm8,

View File

@ -1372,7 +1372,10 @@ DEF_TEST(Image_nonfinite_dst, reporter) {
static sk_sp<SkImage> make_yuva_image(GrDirectContext* dContext) { static sk_sp<SkImage> make_yuva_image(GrDirectContext* dContext) {
SkAutoPixmapStorage pm; SkAutoPixmapStorage pm;
pm.alloc(SkImageInfo::Make(1, 1, kAlpha_8_SkColorType, kPremul_SkAlphaType)); pm.alloc(SkImageInfo::Make(1, 1, kAlpha_8_SkColorType, kPremul_SkAlphaType));
SkYUVAInfo yuvaInfo({1, 1}, SkYUVAInfo::PlanarConfig::kY_U_V_444, kJPEG_Full_SkYUVColorSpace); SkYUVAInfo yuvaInfo({1, 1},
SkYUVAInfo::PlaneConfig::kY_U_V,
SkYUVAInfo::Subsampling::k444,
kJPEG_Full_SkYUVColorSpace);
const SkPixmap pmaps[] = {pm, pm, pm}; const SkPixmap pmaps[] = {pm, pm, pm};
auto yuvaPixmaps = SkYUVAPixmaps::FromExternalPixmaps(yuvaInfo, pmaps); auto yuvaPixmaps = SkYUVAPixmaps::FromExternalPixmaps(yuvaInfo, pmaps);

View File

@ -34,7 +34,8 @@ DEF_TEST(YUVPlanesCache, reporter) {
SkResourceCache cache(1024); SkResourceCache cache(1024);
SkYUVAInfo yuvaInfo({5, 5}, SkYUVAInfo yuvaInfo({5, 5},
SkYUVAInfo::PlanarConfig::kY_U_V_420, SkYUVAInfo::PlaneConfig::kY_U_V,
SkYUVAInfo::Subsampling::k420,
kRec601_Limited_SkYUVColorSpace); kRec601_Limited_SkYUVColorSpace);
SkYUVAPixmapInfo yuvaPixmapInfo(yuvaInfo, SkYUVAPixmapInfo yuvaPixmapInfo(yuvaInfo,
SkYUVAPixmapInfo::DataType::kUnorm8, SkYUVAPixmapInfo::DataType::kUnorm8,

View File

@ -82,39 +82,40 @@ static void codec_yuv(skiatest::Reporter* reporter,
} }
DEF_TEST(Jpeg_YUV_Codec, r) { DEF_TEST(Jpeg_YUV_Codec, r) {
auto setExpectations = [](SkISize dims, SkYUVAInfo::PlanarConfig planarConfig) { auto setExpectations = [](SkISize dims, SkYUVAInfo::Subsampling subsampling) {
return SkYUVAInfo(dims, return SkYUVAInfo(dims,
planarConfig, SkYUVAInfo::PlaneConfig::kY_U_V,
subsampling,
kJPEG_Full_SkYUVColorSpace, kJPEG_Full_SkYUVColorSpace,
kTopLeft_SkEncodedOrigin, kTopLeft_SkEncodedOrigin,
SkYUVAInfo::Siting::kCentered, SkYUVAInfo::Siting::kCentered,
SkYUVAInfo::Siting::kCentered); SkYUVAInfo::Siting::kCentered);
}; };
SkYUVAInfo expectations = setExpectations({128, 128}, SkYUVAInfo::PlanarConfig::kY_U_V_420); SkYUVAInfo expectations = setExpectations({128, 128}, SkYUVAInfo::Subsampling::k420);
codec_yuv(r, "images/color_wheel.jpg", &expectations); codec_yuv(r, "images/color_wheel.jpg", &expectations);
// H2V2 // H2V2
expectations = setExpectations({512, 512}, SkYUVAInfo::PlanarConfig::kY_U_V_420); expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k420);
codec_yuv(r, "images/mandrill_512_q075.jpg", &expectations); codec_yuv(r, "images/mandrill_512_q075.jpg", &expectations);
// H1V1 // H1V1
expectations = setExpectations({512, 512}, SkYUVAInfo::PlanarConfig::kY_U_V_444); expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k444);
codec_yuv(r, "images/mandrill_h1v1.jpg", &expectations); codec_yuv(r, "images/mandrill_h1v1.jpg", &expectations);
// H2V1 // H2V1
expectations = setExpectations({512, 512}, SkYUVAInfo::PlanarConfig::kY_U_V_422); expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k422);
codec_yuv(r, "images/mandrill_h2v1.jpg", &expectations); codec_yuv(r, "images/mandrill_h2v1.jpg", &expectations);
// Non-power of two dimensions // Non-power of two dimensions
expectations = setExpectations({439, 154}, SkYUVAInfo::PlanarConfig::kY_U_V_420); expectations = setExpectations({439, 154}, SkYUVAInfo::Subsampling::k420);
codec_yuv(r, "images/cropped_mandrill.jpg", &expectations); codec_yuv(r, "images/cropped_mandrill.jpg", &expectations);
expectations = setExpectations({8, 8}, SkYUVAInfo::PlanarConfig::kY_U_V_420); expectations = setExpectations({8, 8}, SkYUVAInfo::Subsampling::k420);
codec_yuv(r, "images/randPixels.jpg", &expectations); codec_yuv(r, "images/randPixels.jpg", &expectations);
// Progressive images // Progressive images
expectations = setExpectations({512, 512}, SkYUVAInfo::PlanarConfig::kY_U_V_444); expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k444);
codec_yuv(r, "images/brickwork-texture.jpg", &expectations); codec_yuv(r, "images/brickwork-texture.jpg", &expectations);
codec_yuv(r, "images/brickwork_normal-map.jpg", &expectations); codec_yuv(r, "images/brickwork_normal-map.jpg", &expectations);