1 /*
2 * Copyright 2020 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #ifndef SkYUVAInfo_DEFINED
9 #define SkYUVAInfo_DEFINED
10
11 #include "include/codec/SkEncodedOrigin.h"
12 #include "include/core/SkImageInfo.h"
13 #include "include/core/SkMatrix.h"
14 #include "include/core/SkSize.h"
15 #include "include/core/SkTypes.h"
16
17 #include <array>
18 #include <cstddef>
19 #include <cstdint>
20 #include <tuple>
21
22 /**
23 * Specifies the structure of planes for a YUV image with optional alpha. The actual planar data
24 * is not part of this structure and depending on usage is in external textures or pixmaps.
25 */
26 class SK_API SkYUVAInfo {
27 public:
28 enum YUVAChannels { kY, kU, kV, kA, kLast = kA };
29 static constexpr int kYUVAChannelCount = static_cast<int>(YUVAChannels::kLast + 1);
30
31 struct YUVALocation; // For internal use.
32 using YUVALocations = std::array<YUVALocation, kYUVAChannelCount>;
33
34 /**
35 * Specifies how YUV (and optionally A) are divided among planes. Planes are separated by
36 * underscores in the enum value names. Within each plane the pixmap/texture channels are
37 * mapped to the YUVA channels in the order specified, e.g. for kY_UV Y is in channel 0 of plane
38 * 0, U is in channel 0 of plane 1, and V is in channel 1 of plane 1. Channel ordering
39 * within a pixmap/texture given the channels it contains:
40 * A: 0:A
41 * Luminance/Gray: 0:Gray
42 * Luminance/Gray + Alpha: 0:Gray, 1:A
43 * RG 0:R, 1:G
44 * RGB 0:R, 1:G, 2:B
45 * RGBA 0:R, 1:G, 2:B, 3:A
46 */
47 enum class PlaneConfig {
48 kUnknown,
49
50 kY_U_V, ///< Plane 0: Y, Plane 1: U, Plane 2: V
51 kY_V_U, ///< Plane 0: Y, Plane 1: V, Plane 2: U
52 kY_UV, ///< Plane 0: Y, Plane 1: UV
53 kY_VU, ///< Plane 0: Y, Plane 1: VU
54 kYUV, ///< Plane 0: YUV
55 kUYV, ///< Plane 0: UYV
56
57 kY_U_V_A, ///< Plane 0: Y, Plane 1: U, Plane 2: V, Plane 3: A
58 kY_V_U_A, ///< Plane 0: Y, Plane 1: V, Plane 2: U, Plane 3: A
59 kY_UV_A, ///< Plane 0: Y, Plane 1: UV, Plane 2: A
60 kY_VU_A, ///< Plane 0: Y, Plane 1: VU, Plane 2: A
61 kYUVA, ///< Plane 0: YUVA
62 kUYVA, ///< Plane 0: UYVA
63
64 kLast = kUYVA
65 };
66
67 /**
68 * UV subsampling is also specified in the enum value names using J:a:b notation (e.g. 4:2:0 is
69 * 1/2 horizontal and 1/2 vertical resolution for U and V). If alpha is present it is not sub-
70 * sampled. Note that Subsampling values other than k444 are only valid with PlaneConfig values
71 * that have U and V in different planes than Y (and A, if present).
72 */
73 enum class Subsampling {
74 kUnknown,
75
76 k444, ///< No subsampling. UV values for each Y.
77 k422, ///< 1 set of UV values for each 2x1 block of Y values.
78 k420, ///< 1 set of UV values for each 2x2 block of Y values.
79 k440, ///< 1 set of UV values for each 1x2 block of Y values.
80 k411, ///< 1 set of UV values for each 4x1 block of Y values.
81 k410, ///< 1 set of UV values for each 4x2 block of Y values.
82
83 kLast = k410
84 };
85
86 /**
87 * Describes how subsampled chroma values are sited relative to luma values.
88 *
89 * Currently only centered siting is supported but will expand to support additional sitings.
90 */
91 enum class Siting {
92 /**
93 * Subsampled chroma value is sited at the center of the block of corresponding luma values.
94 */
95 kCentered,
96 };
97
98 static constexpr int kMaxPlanes = 4;
99
100 /** ratio of Y/A values to U/V values in x and y. */
101 static std::tuple<int, int> SubsamplingFactors(Subsampling);
102
103 /**
104 * SubsamplingFactors(Subsampling) if planedIdx refers to a U/V plane and otherwise {1, 1} if
105 * inputs are valid. Invalid inputs consist of incompatible PlaneConfig/Subsampling/planeIdx
106 * combinations. {0, 0} is returned for invalid inputs.
107 */
108 static std::tuple<int, int> PlaneSubsamplingFactors(PlaneConfig, Subsampling, int planeIdx);
109
110 /**
111 * Given image dimensions, a planer configuration, subsampling, and origin, determine the
112 * expected size of each plane. Returns the number of expected planes. planeDimensions[0]
113 * through planeDimensions[<ret>] are written. The input image dimensions are as displayed
114 * (after the planes have been transformed to the intended display orientation). The plane
115 * dimensions are output as the planes are stored in memory (may be rotated from image
116 * dimensions).
117 */
118 static int PlaneDimensions(SkISize imageDimensions,
119 PlaneConfig,
120 Subsampling,
121 SkEncodedOrigin,
122 SkISize planeDimensions[kMaxPlanes]);
123
124 /** Number of planes for a given PlaneConfig. */
125 static constexpr int NumPlanes(PlaneConfig);
126
127 /**
128 * Number of Y, U, V, A channels in the ith plane for a given PlaneConfig (or 0 if i is
129 * invalid).
130 */
131 static constexpr int NumChannelsInPlane(PlaneConfig, int i);
132
133 /**
134 * Given a PlaneConfig and a set of channel flags for each plane, convert to YUVALocations
135 * representation. Fails if channel flags aren't valid for the PlaneConfig (i.e. don't have
136 * enough channels in a plane) by returning an invalid set of locations (plane indices are -1).
137 */
138 static YUVALocations GetYUVALocations(PlaneConfig, const uint32_t* planeChannelFlags);
139
140 /** Does the PlaneConfig have alpha values? */
141 static bool HasAlpha(PlaneConfig);
142
143 SkYUVAInfo() = default;
144 SkYUVAInfo(const SkYUVAInfo&) = default;
145
146 /**
147 * 'dimensions' should specify the size of the full resolution image (after planes have been
148 * oriented to how the image is displayed as indicated by 'origin').
149 */
150 SkYUVAInfo(SkISize dimensions,
151 PlaneConfig,
152 Subsampling,
153 SkYUVColorSpace,
154 SkEncodedOrigin origin = kTopLeft_SkEncodedOrigin,
155 Siting sitingX = Siting::kCentered,
156 Siting sitingY = Siting::kCentered);
157
158 SkYUVAInfo& operator=(const SkYUVAInfo& that) = default;
159
planeConfig()160 PlaneConfig planeConfig() const { return fPlaneConfig; }
subsampling()161 Subsampling subsampling() const { return fSubsampling; }
162
planeSubsamplingFactors(int planeIdx)163 std::tuple<int, int> planeSubsamplingFactors(int planeIdx) const {
164 return PlaneSubsamplingFactors(fPlaneConfig, fSubsampling, planeIdx);
165 }
166
167 /**
168 * Dimensions of the full resolution image (after planes have been oriented to how the image
169 * is displayed as indicated by fOrigin).
170 */
dimensions()171 SkISize dimensions() const { return fDimensions; }
width()172 int width() const { return fDimensions.width(); }
height()173 int height() const { return fDimensions.height(); }
174
yuvColorSpace()175 SkYUVColorSpace yuvColorSpace() const { return fYUVColorSpace; }
sitingX()176 Siting sitingX() const { return fSitingX; }
sitingY()177 Siting sitingY() const { return fSitingY; }
178
origin()179 SkEncodedOrigin origin() const { return fOrigin; }
180
originMatrix()181 SkMatrix originMatrix() const {
182 return SkEncodedOriginToMatrix(fOrigin, this->width(), this->height());
183 }
184
hasAlpha()185 bool hasAlpha() const { return HasAlpha(fPlaneConfig); }
186
187 /**
188 * Returns the number of planes and initializes planeDimensions[0]..planeDimensions[<ret>] to
189 * the expected dimensions for each plane. Dimensions are as stored in memory, before
190 * transformation to image display space as indicated by origin().
191 */
planeDimensions(SkISize planeDimensions[kMaxPlanes])192 int planeDimensions(SkISize planeDimensions[kMaxPlanes]) const {
193 return PlaneDimensions(fDimensions, fPlaneConfig, fSubsampling, fOrigin, planeDimensions);
194 }
195
196 /**
197 * Given a per-plane row bytes, determine size to allocate for all planes. Optionally retrieves
198 * the per-plane byte sizes in planeSizes if not null. If total size overflows will return
199 * SIZE_MAX and set all planeSizes to SIZE_MAX.
200 */
201 size_t computeTotalBytes(const size_t rowBytes[kMaxPlanes],
202 size_t planeSizes[kMaxPlanes] = nullptr) const;
203
numPlanes()204 int numPlanes() const { return NumPlanes(fPlaneConfig); }
205
numChannelsInPlane(int i)206 int numChannelsInPlane(int i) const { return NumChannelsInPlane(fPlaneConfig, i); }
207
208 /**
209 * Given a set of channel flags for each plane, converts this->planeConfig() to YUVALocations
210 * representation. Fails if the channel flags aren't valid for the PlaneConfig (i.e. don't have
211 * enough channels in a plane) by returning default initialized locations (all plane indices are
212 * -1).
213 */
214 YUVALocations toYUVALocations(const uint32_t* channelFlags) const;
215
216 /**
217 * Makes a SkYUVAInfo that is identical to this one but with the passed Subsampling. If the
218 * passed Subsampling is not k444 and this info's PlaneConfig is not compatible with chroma
219 * subsampling (because Y is in the same plane as UV) then the result will be an invalid
220 * SkYUVAInfo.
221 */
222 SkYUVAInfo makeSubsampling(SkYUVAInfo::Subsampling) const;
223
224 /**
225 * Makes a SkYUVAInfo that is identical to this one but with the passed dimensions. If the
226 * passed dimensions is empty then the result will be an invalid SkYUVAInfo.
227 */
228 SkYUVAInfo makeDimensions(SkISize) const;
229
230 bool operator==(const SkYUVAInfo& that) const;
231 bool operator!=(const SkYUVAInfo& that) const { return !(*this == that); }
232
isValid()233 bool isValid() const { return fPlaneConfig != PlaneConfig::kUnknown; }
234
235 private:
236 SkISize fDimensions = {0, 0};
237
238 PlaneConfig fPlaneConfig = PlaneConfig::kUnknown;
239 Subsampling fSubsampling = Subsampling::kUnknown;
240
241 SkYUVColorSpace fYUVColorSpace = SkYUVColorSpace::kIdentity_SkYUVColorSpace;
242
243 /**
244 * YUVA data often comes from formats like JPEG that support EXIF orientation.
245 * Code that operates on the raw YUV data often needs to know that orientation.
246 */
247 SkEncodedOrigin fOrigin = kTopLeft_SkEncodedOrigin;
248
249 Siting fSitingX = Siting::kCentered;
250 Siting fSitingY = Siting::kCentered;
251 };
252
NumPlanes(PlaneConfig planeConfig)253 constexpr int SkYUVAInfo::NumPlanes(PlaneConfig planeConfig) {
254 switch (planeConfig) {
255 case PlaneConfig::kUnknown: return 0;
256 case PlaneConfig::kY_U_V: return 3;
257 case PlaneConfig::kY_V_U: return 3;
258 case PlaneConfig::kY_UV: return 2;
259 case PlaneConfig::kY_VU: return 2;
260 case PlaneConfig::kYUV: return 1;
261 case PlaneConfig::kUYV: return 1;
262 case PlaneConfig::kY_U_V_A: return 4;
263 case PlaneConfig::kY_V_U_A: return 4;
264 case PlaneConfig::kY_UV_A: return 3;
265 case PlaneConfig::kY_VU_A: return 3;
266 case PlaneConfig::kYUVA: return 1;
267 case PlaneConfig::kUYVA: return 1;
268 }
269 SkUNREACHABLE;
270 }
271
NumChannelsInPlane(PlaneConfig config,int i)272 constexpr int SkYUVAInfo::NumChannelsInPlane(PlaneConfig config, int i) {
273 switch (config) {
274 case PlaneConfig::kUnknown:
275 return 0;
276
277 case SkYUVAInfo::PlaneConfig::kY_U_V:
278 case SkYUVAInfo::PlaneConfig::kY_V_U:
279 return i >= 0 && i < 3 ? 1 : 0;
280 case SkYUVAInfo::PlaneConfig::kY_UV:
281 case SkYUVAInfo::PlaneConfig::kY_VU:
282 switch (i) {
283 case 0: return 1;
284 case 1: return 2;
285 default: return 0;
286 }
287 case SkYUVAInfo::PlaneConfig::kYUV:
288 case SkYUVAInfo::PlaneConfig::kUYV:
289 return i == 0 ? 3 : 0;
290 case SkYUVAInfo::PlaneConfig::kY_U_V_A:
291 case SkYUVAInfo::PlaneConfig::kY_V_U_A:
292 return i >= 0 && i < 4 ? 1 : 0;
293 case SkYUVAInfo::PlaneConfig::kY_UV_A:
294 case SkYUVAInfo::PlaneConfig::kY_VU_A:
295 switch (i) {
296 case 0: return 1;
297 case 1: return 2;
298 case 2: return 1;
299 default: return 0;
300 }
301 case SkYUVAInfo::PlaneConfig::kYUVA:
302 case SkYUVAInfo::PlaneConfig::kUYVA:
303 return i == 0 ? 4 : 0;
304 }
305 return 0;
306 }
307
308 #endif
309