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