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