Coverage Report

Created: 2024-05-20 07:14

/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/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
0
    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
160
0
    PlaneConfig planeConfig() const { return fPlaneConfig; }
161
0
    Subsampling subsampling() const { return fSubsampling; }
162
163
0
    std::tuple<int, int> planeSubsamplingFactors(int planeIdx) const {
164
0
        return PlaneSubsamplingFactors(fPlaneConfig, fSubsampling, planeIdx);
165
0
    }
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
     */
171
0
    SkISize dimensions() const { return fDimensions; }
172
0
    int width() const { return fDimensions.width(); }
173
0
    int height() const { return fDimensions.height(); }
174
175
0
    SkYUVColorSpace yuvColorSpace() const { return fYUVColorSpace; }
176
0
    Siting sitingX() const { return fSitingX; }
177
0
    Siting sitingY() const { return fSitingY; }
178
179
0
    SkEncodedOrigin origin() const { return fOrigin; }
180
181
0
    SkMatrix originMatrix() const {
182
0
        return SkEncodedOriginToMatrix(fOrigin, this->width(), this->height());
183
0
    }
184
185
0
    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
     */
192
0
    int planeDimensions(SkISize planeDimensions[kMaxPlanes]) const {
193
0
        return PlaneDimensions(fDimensions, fPlaneConfig, fSubsampling, fOrigin, planeDimensions);
194
0
    }
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
204
0
    int numPlanes() const { return NumPlanes(fPlaneConfig); }
205
206
0
    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
0
    bool operator!=(const SkYUVAInfo& that) const { return !(*this == that); }
232
233
0
    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
253
0
constexpr int SkYUVAInfo::NumPlanes(PlaneConfig planeConfig) {
254
0
    switch (planeConfig) {
255
0
        case PlaneConfig::kUnknown: return 0;
256
0
        case PlaneConfig::kY_U_V:   return 3;
257
0
        case PlaneConfig::kY_V_U:   return 3;
258
0
        case PlaneConfig::kY_UV:    return 2;
259
0
        case PlaneConfig::kY_VU:    return 2;
260
0
        case PlaneConfig::kYUV:     return 1;
261
0
        case PlaneConfig::kUYV:     return 1;
262
0
        case PlaneConfig::kY_U_V_A: return 4;
263
0
        case PlaneConfig::kY_V_U_A: return 4;
264
0
        case PlaneConfig::kY_UV_A:  return 3;
265
0
        case PlaneConfig::kY_VU_A:  return 3;
266
0
        case PlaneConfig::kYUVA:    return 1;
267
0
        case PlaneConfig::kUYVA:    return 1;
268
0
    }
269
0
    SkUNREACHABLE;
270
0
}
271
272
0
constexpr int SkYUVAInfo::NumChannelsInPlane(PlaneConfig config, int i) {
273
0
    switch (config) {
274
0
        case PlaneConfig::kUnknown:
275
0
            return 0;
276
277
0
        case SkYUVAInfo::PlaneConfig::kY_U_V:
278
0
        case SkYUVAInfo::PlaneConfig::kY_V_U:
279
0
            return i >= 0 && i < 3 ? 1 : 0;
280
0
        case SkYUVAInfo::PlaneConfig::kY_UV:
281
0
        case SkYUVAInfo::PlaneConfig::kY_VU:
282
0
            switch (i) {
283
0
                case 0:  return 1;
284
0
                case 1:  return 2;
285
0
                default: return 0;
286
0
            }
287
0
        case SkYUVAInfo::PlaneConfig::kYUV:
288
0
        case SkYUVAInfo::PlaneConfig::kUYV:
289
0
            return i == 0 ? 3 : 0;
290
0
        case SkYUVAInfo::PlaneConfig::kY_U_V_A:
291
0
        case SkYUVAInfo::PlaneConfig::kY_V_U_A:
292
0
            return i >= 0 && i < 4 ? 1 : 0;
293
0
        case SkYUVAInfo::PlaneConfig::kY_UV_A:
294
0
        case SkYUVAInfo::PlaneConfig::kY_VU_A:
295
0
            switch (i) {
296
0
                case 0:  return 1;
297
0
                case 1:  return 2;
298
0
                case 2:  return 1;
299
0
                default: return 0;
300
0
            }
301
0
        case SkYUVAInfo::PlaneConfig::kYUVA:
302
0
        case SkYUVAInfo::PlaneConfig::kUYVA:
303
0
            return i == 0 ? 4 : 0;
304
0
    }
305
0
    return 0;
306
0
}
307
308
#endif