Coverage Report

Created: 2021-08-22 09:07

/src/skia/include/core/SkYUVAInfo.h
Line
Count
Source (jump to first uncovered line)
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
0
    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
156
0
    PlaneConfig planeConfig() const { return fPlaneConfig; }
157
0
    Subsampling subsampling() const { return fSubsampling; }
158
159
0
    std::tuple<int, int> planeSubsamplingFactors(int planeIdx) const {
160
0
        return PlaneSubsamplingFactors(fPlaneConfig, fSubsampling, planeIdx);
161
0
    }
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
     */
167
0
    SkISize dimensions() const { return fDimensions; }
168
0
    int width() const { return fDimensions.width(); }
169
0
    int height() const { return fDimensions.height(); }
170
171
0
    SkYUVColorSpace yuvColorSpace() const { return fYUVColorSpace; }
172
0
    Siting sitingX() const { return fSitingX; }
173
0
    Siting sitingY() const { return fSitingY; }
174
175
0
    SkEncodedOrigin origin() const { return fOrigin; }
176
177
0
    SkMatrix originMatrix() const {
178
0
        return SkEncodedOriginToMatrix(fOrigin, this->width(), this->height());
179
0
    }
180
181
0
    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
     */
188
0
    int planeDimensions(SkISize planeDimensions[kMaxPlanes]) const {
189
0
        return PlaneDimensions(fDimensions, fPlaneConfig, fSubsampling, fOrigin, planeDimensions);
190
0
    }
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
200
0
    int numPlanes() const { return NumPlanes(fPlaneConfig); }
201
202
0
    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
0
    bool operator!=(const SkYUVAInfo& that) const { return !(*this == that); }
228
229
0
    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
249
0
constexpr int SkYUVAInfo::NumPlanes(PlaneConfig planeConfig) {
250
0
    switch (planeConfig) {
251
0
        case PlaneConfig::kUnknown: return 0;
252
0
        case PlaneConfig::kY_U_V:   return 3;
253
0
        case PlaneConfig::kY_V_U:   return 3;
254
0
        case PlaneConfig::kY_UV:    return 2;
255
0
        case PlaneConfig::kY_VU:    return 2;
256
0
        case PlaneConfig::kYUV:     return 1;
257
0
        case PlaneConfig::kUYV:     return 1;
258
0
        case PlaneConfig::kY_U_V_A: return 4;
259
0
        case PlaneConfig::kY_V_U_A: return 4;
260
0
        case PlaneConfig::kY_UV_A:  return 3;
261
0
        case PlaneConfig::kY_VU_A:  return 3;
262
0
        case PlaneConfig::kYUVA:    return 1;
263
0
        case PlaneConfig::kUYVA:    return 1;
264
0
    }
265
0
    SkUNREACHABLE;
266
0
}
267
268
0
constexpr int SkYUVAInfo::NumChannelsInPlane(PlaneConfig config, int i) {
269
0
    switch (config) {
270
0
        case PlaneConfig::kUnknown:
271
0
            return 0;
272
273
0
        case SkYUVAInfo::PlaneConfig::kY_U_V:
274
0
        case SkYUVAInfo::PlaneConfig::kY_V_U:
275
0
            return i >= 0 && i < 3 ? 1 : 0;
276
0
        case SkYUVAInfo::PlaneConfig::kY_UV:
277
0
        case SkYUVAInfo::PlaneConfig::kY_VU:
278
0
            switch (i) {
279
0
                case 0:  return 1;
280
0
                case 1:  return 2;
281
0
                default: return 0;
282
0
            }
283
0
        case SkYUVAInfo::PlaneConfig::kYUV:
284
0
        case SkYUVAInfo::PlaneConfig::kUYV:
285
0
            return i == 0 ? 3 : 0;
286
0
        case SkYUVAInfo::PlaneConfig::kY_U_V_A:
287
0
        case SkYUVAInfo::PlaneConfig::kY_V_U_A:
288
0
            return i >= 0 && i < 4 ? 1 : 0;
289
0
        case SkYUVAInfo::PlaneConfig::kY_UV_A:
290
0
        case SkYUVAInfo::PlaneConfig::kY_VU_A:
291
0
            switch (i) {
292
0
                case 0:  return 1;
293
0
                case 1:  return 2;
294
0
                case 2:  return 1;
295
0
                default: return 0;
296
0
            }
297
0
        case SkYUVAInfo::PlaneConfig::kYUVA:
298
0
        case SkYUVAInfo::PlaneConfig::kUYVA:
299
0
            return i == 0 ? 4 : 0;
300
0
    }
301
0
    return 0;
302
0
}
303
304
#endif