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