1 /*
2 * Copyright 2019 Google Inc.
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 #include "src/core/SkYUVMath.h"
9
10 #include "include/core/SkImageInfo.h"
11 #include "include/core/SkM44.h"
12 #include "include/private/base/SkAssert.h"
13 #include "include/private/base/SkDebug.h"
14
15 #include <cstring>
16
17 // in SkColorMatrix order (row-major)
18 // Created by running SkColorMatrix_DumpYUVMatrixTables()
19 const float JPEG_full_rgb_to_yuv[] = {
20 0.299000f, 0.587000f, 0.114000f, 0.000000f, 0.000000f,
21 -0.168736f, -0.331264f, 0.500000f, 0.000000f, 0.501961f,
22 0.500000f, -0.418688f, -0.081312f, 0.000000f, 0.501961f,
23 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
24 };
25 const float JPEG_full_yuv_to_rgb[] = {
26 1.000000f, -0.000000f, 1.402000f, 0.000000f, -0.703749f,
27 1.000000f, -0.344136f, -0.714136f, 0.000000f, 0.531211f,
28 1.000000f, 1.772000f, 0.000000f, 0.000000f, -0.889475f,
29 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
30 };
31 const float Rec601_limited_rgb_to_yuv[] = {
32 0.256788f, 0.504129f, 0.097906f, 0.000000f, 0.062745f,
33 -0.148223f, -0.290993f, 0.439216f, 0.000000f, 0.501961f,
34 0.439216f, -0.367788f, -0.071427f, 0.000000f, 0.501961f,
35 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
36 };
37 const float Rec601_limited_yuv_to_rgb[] = {
38 1.164384f, -0.000000f, 1.596027f, 0.000000f, -0.874202f,
39 1.164384f, -0.391762f, -0.812968f, 0.000000f, 0.531668f,
40 1.164384f, 2.017232f, 0.000000f, 0.000000f, -1.085631f,
41 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
42 };
43 const float Rec709_full_rgb_to_yuv[] = {
44 0.212600f, 0.715200f, 0.072200f, 0.000000f, 0.000000f,
45 -0.114572f, -0.385428f, 0.500000f, 0.000000f, 0.501961f,
46 0.500000f, -0.454153f, -0.045847f, 0.000000f, 0.501961f,
47 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
48 };
49 const float Rec709_full_yuv_to_rgb[] = {
50 1.000000f, -0.000000f, 1.574800f, 0.000000f, -0.790488f,
51 1.000000f, -0.187324f, -0.468124f, 0.000000f, 0.329010f,
52 1.000000f, 1.855600f, -0.000000f, 0.000000f, -0.931439f,
53 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
54 };
55 const float Rec709_limited_rgb_to_yuv[] = {
56 0.182586f, 0.614231f, 0.062007f, 0.000000f, 0.062745f,
57 -0.100644f, -0.338572f, 0.439216f, 0.000000f, 0.501961f,
58 0.439216f, -0.398942f, -0.040274f, 0.000000f, 0.501961f,
59 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
60 };
61 const float Rec709_limited_yuv_to_rgb[] = {
62 1.164384f, -0.000000f, 1.792741f, 0.000000f, -0.972945f,
63 1.164384f, -0.213249f, -0.532909f, 0.000000f, 0.301483f,
64 1.164384f, 2.112402f, -0.000000f, 0.000000f, -1.133402f,
65 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
66 };
67 const float BT2020_8bit_full_rgb_to_yuv[] = {
68 0.262700f, 0.678000f, 0.059300f, 0.000000f, 0.000000f,
69 -0.139630f, -0.360370f, 0.500000f, 0.000000f, 0.501961f,
70 0.500000f, -0.459786f, -0.040214f, 0.000000f, 0.501961f,
71 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
72 };
73 const float BT2020_8bit_full_yuv_to_rgb[] = {
74 1.000000f, -0.000000f, 1.474600f, 0.000000f, -0.740191f,
75 1.000000f, -0.164553f, -0.571353f, 0.000000f, 0.369396f,
76 1.000000f, 1.881400f, -0.000000f, 0.000000f, -0.944389f,
77 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
78 };
79 const float BT2020_8bit_limited_rgb_to_yuv[] = {
80 0.225613f, 0.582282f, 0.050928f, 0.000000f, 0.062745f,
81 -0.122655f, -0.316560f, 0.439216f, 0.000000f, 0.501961f,
82 0.439216f, -0.403890f, -0.035326f, 0.000000f, 0.501961f,
83 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
84 };
85 const float BT2020_8bit_limited_yuv_to_rgb[] = {
86 1.164384f, -0.000000f, 1.678674f, 0.000000f, -0.915688f,
87 1.164384f, -0.187326f, -0.650424f, 0.000000f, 0.347458f,
88 1.164384f, 2.141772f, -0.000000f, 0.000000f, -1.148145f,
89 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
90 };
91 const float BT2020_10bit_full_rgb_to_yuv[] = {
92 0.262700f, 0.678000f, 0.059300f, 0.000000f, 0.000000f,
93 -0.139630f, -0.360370f, 0.500000f, 0.000000f, 0.500489f,
94 0.500000f, -0.459786f, -0.040214f, 0.000000f, 0.500489f,
95 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
96 };
97 const float BT2020_10bit_full_yuv_to_rgb[] = {
98 1.000000f, -0.000000f, 1.474600f, 0.000000f, -0.738021f,
99 1.000000f, -0.164553f, -0.571353f, 0.000000f, 0.368313f,
100 1.000000f, 1.881400f, -0.000000f, 0.000000f, -0.941620f,
101 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
102 };
103 const float BT2020_10bit_limited_rgb_to_yuv[] = {
104 0.224951f, 0.580575f, 0.050779f, 0.000000f, 0.062561f,
105 -0.122296f, -0.315632f, 0.437928f, 0.000000f, 0.500489f,
106 0.437928f, -0.402706f, -0.035222f, 0.000000f, 0.500489f,
107 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
108 };
109 const float BT2020_10bit_limited_yuv_to_rgb[] = {
110 1.167808f, -0.000000f, 1.683611f, 0.000000f, -0.915688f,
111 1.167808f, -0.187877f, -0.652337f, 0.000000f, 0.347458f,
112 1.167808f, 2.148072f, -0.000000f, 0.000000f, -1.148145f,
113 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
114 };
115 const float BT2020_12bit_full_rgb_to_yuv[] = {
116 0.262700f, 0.678000f, 0.059300f, 0.000000f, 0.000000f,
117 -0.139630f, -0.360370f, 0.500000f, 0.000000f, 0.500122f,
118 0.500000f, -0.459786f, -0.040214f, 0.000000f, 0.500122f,
119 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
120 };
121 const float BT2020_12bit_full_yuv_to_rgb[] = {
122 1.000000f, -0.000000f, 1.474600f, 0.000000f, -0.737480f,
123 1.000000f, -0.164553f, -0.571353f, 0.000000f, 0.368043f,
124 1.000000f, 1.881400f, -0.000000f, 0.000000f, -0.940930f,
125 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
126 };
127 const float BT2020_12bit_limited_rgb_to_yuv[] = {
128 0.224787f, 0.580149f, 0.050742f, 0.000000f, 0.062515f,
129 -0.122206f, -0.315401f, 0.437607f, 0.000000f, 0.500122f,
130 0.437607f, -0.402411f, -0.035196f, 0.000000f, 0.500122f,
131 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
132 };
133 const float BT2020_12bit_limited_yuv_to_rgb[] = {
134 1.168664f, -0.000000f, 1.684846f, 0.000000f, -0.915688f,
135 1.168664f, -0.188015f, -0.652816f, 0.000000f, 0.347458f,
136 1.168664f, 2.149647f, -0.000000f, 0.000000f, -1.148145f,
137 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
138 };
139 const float FCC_full_rgb_to_yuv[] = {
140 0.300000f, 0.590000f, 0.110000f, 0.000000f, 0.000000f,
141 -0.168539f, -0.331461f, 0.500000f, 0.000000f, 0.501961f,
142 0.500000f, -0.421429f, -0.078571f, 0.000000f, 0.501961f,
143 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
144 };
145 const float FCC_full_yuv_to_rgb[] = {
146 1.000000f, 0.000000f, 1.400000f, 0.000000f, -0.702745f,
147 1.000000f, -0.331864f, -0.711864f, 0.000000f, 0.523911f,
148 1.000000f, 1.780000f, 0.000000f, 0.000000f, -0.893490f,
149 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
150 };
151 const float FCC_limited_rgb_to_yuv[] = {
152 0.257647f, 0.506706f, 0.094471f, 0.000000f, 0.062745f,
153 -0.148050f, -0.291165f, 0.439216f, 0.000000f, 0.501961f,
154 0.439216f, -0.370196f, -0.069020f, 0.000000f, 0.501961f,
155 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
156 };
157 const float FCC_limited_yuv_to_rgb[] = {
158 1.164384f, -0.000000f, 1.593750f, 0.000000f, -0.873059f,
159 1.164384f, -0.377792f, -0.810381f, 0.000000f, 0.523357f,
160 1.164384f, 2.026339f, 0.000000f, 0.000000f, -1.090202f,
161 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
162 };
163 const float SMPTE240_full_rgb_to_yuv[] = {
164 0.212000f, 0.701000f, 0.087000f, 0.000000f, 0.000000f,
165 -0.116101f, -0.383899f, 0.500000f, 0.000000f, 0.501961f,
166 0.500000f, -0.444797f, -0.055203f, 0.000000f, 0.501961f,
167 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
168 };
169 const float SMPTE240_full_yuv_to_rgb[] = {
170 1.000000f, 0.000000f, 1.576000f, 0.000000f, -0.791090f,
171 1.000000f, -0.226622f, -0.476622f, 0.000000f, 0.353001f,
172 1.000000f, 1.826000f, 0.000000f, 0.000000f, -0.916580f,
173 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
174 };
175 const float SMPTE240_limited_rgb_to_yuv[] = {
176 0.182071f, 0.602035f, 0.074718f, 0.000000f, 0.062745f,
177 -0.101987f, -0.337229f, 0.439216f, 0.000000f, 0.501961f,
178 0.439216f, -0.390724f, -0.048492f, 0.000000f, 0.501961f,
179 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
180 };
181 const float SMPTE240_limited_yuv_to_rgb[] = {
182 1.164384f, -0.000000f, 1.794107f, 0.000000f, -0.973631f,
183 1.164384f, -0.257985f, -0.542583f, 0.000000f, 0.328794f,
184 1.164384f, 2.078705f, 0.000000f, 0.000000f, -1.116488f,
185 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
186 };
187 const float YDZDX_full_rgb_to_yuv[] = {
188 0.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f,
189 0.000000f, -0.500000f, 0.493283f, 0.000000f, 0.501961f,
190 0.500000f, -0.495951f, 0.000000f, 0.000000f, 0.501961f,
191 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
192 };
193 const float YDZDX_full_yuv_to_rgb[] = {
194 0.991902f, -0.000000f, 2.000000f, 0.000000f, -1.003922f,
195 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
196 1.013617f, 2.027234f, 0.000000f, 0.000000f, -1.017592f,
197 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
198 };
199 const float YDZDX_limited_rgb_to_yuv[] = {
200 0.000000f, 0.858824f, 0.000000f, 0.000000f, 0.062745f,
201 0.000000f, -0.439216f, 0.433315f, 0.000000f, 0.501961f,
202 0.439216f, -0.435659f, 0.000000f, 0.000000f, 0.501961f,
203 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
204 };
205 const float YDZDX_limited_yuv_to_rgb[] = {
206 1.154954f, -0.000000f, 2.276786f, 0.000000f, -1.215325f,
207 1.164384f, 0.000000f, 0.000000f, 0.000000f, -0.073059f,
208 1.180239f, 2.307788f, 0.000000f, 0.000000f, -1.232474f,
209 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
210 };
211 const float GBR_full_rgb_to_yuv[] = {
212 0.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f,
213 0.000000f, 0.000000f, 1.000000f, 0.000000f, 0.000000f,
214 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
215 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
216 };
217 const float GBR_full_yuv_to_rgb[] = {
218 0.000000f, 0.000000f, 1.000000f, 0.000000f, 0.000000f,
219 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
220 0.000000f, 1.000000f, 0.000000f, 0.000000f, -0.000000f,
221 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
222 };
223 const float GBR_limited_rgb_to_yuv[] = {
224 0.000000f, 0.858824f, 0.000000f, 0.000000f, 0.062745f,
225 0.000000f, 0.000000f, 0.858824f, 0.000000f, 0.062745f,
226 0.858824f, 0.000000f, 0.000000f, 0.000000f, 0.062745f,
227 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
228 };
229 const float GBR_limited_yuv_to_rgb[] = {
230 0.000000f, 0.000000f, 1.164384f, 0.000000f, -0.073059f,
231 1.164384f, 0.000000f, 0.000000f, 0.000000f, -0.073059f,
232 0.000000f, 1.164384f, 0.000000f, 0.000000f, -0.073059f,
233 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
234 };
235 const float YCgCo_8bit_full_rgb_to_yuv[] = {
236 0.250000f, 0.500000f, 0.250000f, 0.000000f, 0.000000f,
237 -0.250000f, 0.500000f, -0.250000f, 0.000000f, 0.501961f,
238 0.500000f, 0.000000f, -0.500000f, 0.000000f, 0.501961f,
239 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
240 };
241 const float YCgCo_8bit_full_yuv_to_rgb[] = {
242 1.000000f, -1.000000f, 1.000000f, 0.000000f, 0.000000f,
243 1.000000f, 1.000000f, 0.000000f, 0.000000f, -0.501961f,
244 1.000000f, -1.000000f, -1.000000f, 0.000000f, 1.003922f,
245 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
246 };
247 const float YCgCo_8bit_limited_rgb_to_yuv[] = {
248 0.214706f, 0.429412f, 0.214706f, 0.000000f, 0.062745f,
249 -0.214706f, 0.429412f, -0.214706f, 0.000000f, 0.501961f,
250 0.429412f, 0.000000f, -0.429412f, 0.000000f, 0.501961f,
251 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
252 };
253 const float YCgCo_8bit_limited_yuv_to_rgb[] = {
254 1.164384f, -1.164384f, 1.164384f, 0.000000f, -0.073059f,
255 1.164384f, 1.164384f, 0.000000f, 0.000000f, -0.657534f,
256 1.164384f, -1.164384f, -1.164384f, 0.000000f, 1.095891f,
257 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
258 };
259 const float YCgCo_10bit_full_rgb_to_yuv[] = {
260 0.250000f, 0.500000f, 0.250000f, 0.000000f, 0.000000f,
261 -0.250000f, 0.500000f, -0.250000f, 0.000000f, 0.500489f,
262 0.500000f, 0.000000f, -0.500000f, 0.000000f, 0.500489f,
263 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
264 };
265 const float YCgCo_10bit_full_yuv_to_rgb[] = {
266 1.000000f, -1.000000f, 1.000000f, 0.000000f, 0.000000f,
267 1.000000f, 1.000000f, 0.000000f, 0.000000f, -0.500489f,
268 1.000000f, -1.000000f, -1.000000f, 0.000000f, 1.000978f,
269 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
270 };
271 const float YCgCo_10bit_limited_rgb_to_yuv[] = {
272 0.214076f, 0.428153f, 0.214076f, 0.000000f, 0.062561f,
273 -0.214076f, 0.428153f, -0.214076f, 0.000000f, 0.500489f,
274 0.428153f, 0.000000f, -0.428153f, 0.000000f, 0.500489f,
275 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
276 };
277 const float YCgCo_10bit_limited_yuv_to_rgb[] = {
278 1.167808f, -1.167808f, 1.167808f, 0.000000f, -0.073059f,
279 1.167808f, 1.167808f, 0.000000f, 0.000000f, -0.657534f,
280 1.167808f, -1.167808f, -1.167808f, 0.000000f, 1.095890f,
281 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
282 };
283 const float YCgCo_12bit_full_rgb_to_yuv[] = {
284 0.250000f, 0.500000f, 0.250000f, 0.000000f, 0.000000f,
285 -0.250000f, 0.500000f, -0.250000f, 0.000000f, 0.500122f,
286 0.500000f, 0.000000f, -0.500000f, 0.000000f, 0.500122f,
287 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
288 };
289 const float YCgCo_12bit_full_yuv_to_rgb[] = {
290 1.000000f, -1.000000f, 1.000000f, 0.000000f, 0.000000f,
291 1.000000f, 1.000000f, 0.000000f, 0.000000f, -0.500122f,
292 1.000000f, -1.000000f, -1.000000f, 0.000000f, 1.000244f,
293 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
294 };
295 const float YCgCo_12bit_limited_rgb_to_yuv[] = {
296 0.213919f, 0.427839f, 0.213919f, 0.000000f, 0.062515f,
297 -0.213919f, 0.427839f, -0.213919f, 0.000000f, 0.500122f,
298 0.427839f, 0.000000f, -0.427839f, 0.000000f, 0.500122f,
299 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
300 };
301 const float YCgCo_12bit_limited_yuv_to_rgb[] = {
302 1.168664f, -1.168664f, 1.168664f, 0.000000f, -0.073059f,
303 1.168664f, 1.168664f, 0.000000f, 0.000000f, -0.657534f,
304 1.168664f, -1.168664f, -1.168664f, 0.000000f, 1.095891f,
305 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
306 };
307
308 static_assert(kJPEG_Full_SkYUVColorSpace == 0, "");
309 static_assert(kRec601_Limited_SkYUVColorSpace == 1, "");
310 static_assert(kRec709_Full_SkYUVColorSpace == 2, "");
311 static_assert(kRec709_Limited_SkYUVColorSpace == 3, "");
312 static_assert(kBT2020_8bit_Full_SkYUVColorSpace == 4, "");
313 static_assert(kBT2020_8bit_Limited_SkYUVColorSpace == 5, "");
314 static_assert(kBT2020_10bit_Full_SkYUVColorSpace == 6, "");
315 static_assert(kBT2020_10bit_Limited_SkYUVColorSpace == 7, "");
316 static_assert(kBT2020_12bit_Full_SkYUVColorSpace == 8, "");
317 static_assert(kBT2020_12bit_Limited_SkYUVColorSpace == 9, "");
318 static_assert(kFCC_Full_SkYUVColorSpace == 10, "");
319 static_assert(kFCC_Limited_SkYUVColorSpace == 11, "");
320 static_assert(kSMPTE240_Full_SkYUVColorSpace == 12, "");
321 static_assert(kSMPTE240_Limited_SkYUVColorSpace == 13, "");
322 static_assert(kYDZDX_Full_SkYUVColorSpace == 14, "");
323 static_assert(kYDZDX_Limited_SkYUVColorSpace == 15, "");
324 static_assert(kGBR_Full_SkYUVColorSpace == 16, "");
325 static_assert(kGBR_Limited_SkYUVColorSpace == 17, "");
326 static_assert(kYCgCo_8bit_Full_SkYUVColorSpace == 18, "");
327 static_assert(kYCgCo_8bit_Limited_SkYUVColorSpace == 19, "");
328 static_assert(kYCgCo_10bit_Full_SkYUVColorSpace == 20, "");
329 static_assert(kYCgCo_10bit_Limited_SkYUVColorSpace == 21, "");
330 static_assert(kYCgCo_12bit_Full_SkYUVColorSpace == 22, "");
331 static_assert(kYCgCo_12bit_Limited_SkYUVColorSpace == 23, "");
332
333 const float* yuv_to_rgb_array[] = {
334 JPEG_full_yuv_to_rgb,
335 Rec601_limited_yuv_to_rgb,
336 Rec709_full_yuv_to_rgb,
337 Rec709_limited_yuv_to_rgb,
338 BT2020_8bit_full_yuv_to_rgb,
339 BT2020_8bit_limited_yuv_to_rgb,
340 BT2020_10bit_full_yuv_to_rgb,
341 BT2020_10bit_limited_yuv_to_rgb,
342 BT2020_12bit_full_yuv_to_rgb,
343 BT2020_12bit_limited_yuv_to_rgb,
344 FCC_full_yuv_to_rgb,
345 FCC_limited_yuv_to_rgb,
346 SMPTE240_full_yuv_to_rgb,
347 SMPTE240_limited_yuv_to_rgb,
348 YDZDX_full_yuv_to_rgb,
349 YDZDX_limited_yuv_to_rgb,
350 GBR_full_yuv_to_rgb,
351 GBR_limited_yuv_to_rgb,
352 YCgCo_8bit_full_yuv_to_rgb,
353 YCgCo_8bit_limited_yuv_to_rgb,
354 YCgCo_10bit_full_yuv_to_rgb,
355 YCgCo_10bit_limited_yuv_to_rgb,
356 YCgCo_12bit_full_yuv_to_rgb,
357 YCgCo_12bit_limited_yuv_to_rgb,
358 };
359
360 const float* rgb_to_yuv_array[] = {
361 JPEG_full_rgb_to_yuv,
362 Rec601_limited_rgb_to_yuv,
363 Rec709_full_rgb_to_yuv,
364 Rec709_limited_rgb_to_yuv,
365 BT2020_8bit_full_rgb_to_yuv,
366 BT2020_8bit_limited_rgb_to_yuv,
367 BT2020_10bit_full_rgb_to_yuv,
368 BT2020_10bit_limited_rgb_to_yuv,
369 BT2020_12bit_full_rgb_to_yuv,
370 BT2020_12bit_limited_rgb_to_yuv,
371 FCC_full_rgb_to_yuv,
372 FCC_limited_rgb_to_yuv,
373 SMPTE240_full_rgb_to_yuv,
374 SMPTE240_limited_rgb_to_yuv,
375 YDZDX_full_rgb_to_yuv,
376 YDZDX_limited_rgb_to_yuv,
377 GBR_full_rgb_to_yuv,
378 GBR_limited_rgb_to_yuv,
379 YCgCo_8bit_full_rgb_to_yuv,
380 YCgCo_8bit_limited_rgb_to_yuv,
381 YCgCo_10bit_full_rgb_to_yuv,
382 YCgCo_10bit_limited_rgb_to_yuv,
383 YCgCo_12bit_full_rgb_to_yuv,
384 YCgCo_12bit_limited_rgb_to_yuv,
385 };
386
387 constexpr size_t kSizeOfColorMatrix = 20 * sizeof(float);
388
SkColorMatrix_RGB2YUV(SkYUVColorSpace cs,float m[20])389 void SkColorMatrix_RGB2YUV(SkYUVColorSpace cs, float m[20]) {
390 if ((unsigned)cs < (unsigned)kIdentity_SkYUVColorSpace) {
391 memcpy(m, rgb_to_yuv_array[(unsigned)cs], kSizeOfColorMatrix);
392 } else {
393 memset(m, 0, kSizeOfColorMatrix);
394 m[0] = m[6] = m[12] = m[18] = 1;
395 }
396 }
397
SkColorMatrix_YUV2RGB(SkYUVColorSpace cs,float m[20])398 void SkColorMatrix_YUV2RGB(SkYUVColorSpace cs, float m[20]) {
399 if ((unsigned)cs < (unsigned)kIdentity_SkYUVColorSpace) {
400 memcpy(m, yuv_to_rgb_array[(unsigned)cs], kSizeOfColorMatrix);
401 } else {
402 memset(m, 0, kSizeOfColorMatrix);
403 m[0] = m[6] = m[12] = m[18] = 1;
404 }
405 }
406
407 ///////////////////////////////////////////////////////////////////////////////////////////////////
408
409 // we just drop the alpha rol/col from the colormatrix
410 // output is | tr |
411 // | 3x3 tg |
412 // | tb |
413 // | 0 0 0 1 |
colormatrix_to_matrix44(const float src[20],SkM44 * dst)414 static void colormatrix_to_matrix44(const float src[20], SkM44* dst) {
415 *dst = SkM44(src[ 0], src[ 1], src[ 2], src[ 4],
416 src[ 5], src[ 6], src[ 7], src[ 9],
417 src[10], src[11], src[12], src[14],
418 0, 0, 0, 1);
419 }
420
421 // input: ignore the bottom row
422 // output: inject identity row/column for alpha
matrix44_to_colormatrix(const SkM44 & src,float dst[20])423 static void matrix44_to_colormatrix(const SkM44& src, float dst[20]) {
424 dst[0] = src.rc(0,0);
425 dst[1] = src.rc(0,1);
426 dst[2] = src.rc(0,2);
427 dst[3] = 0;
428 dst[4] = src.rc(0,3); // tx
429
430 dst[5] = src.rc(1,0);
431 dst[6] = src.rc(1,1);
432 dst[7] = src.rc(1,2);
433 dst[8] = 0;
434 dst[9] = src.rc(1,3); // ty
435
436 dst[10] = src.rc(2,0);
437 dst[11] = src.rc(2,1);
438 dst[12] = src.rc(2,2);
439 dst[13] = 0;
440 dst[14] = src.rc(2,3); // tz
441
442 dst[15] = dst[16] = dst[17] = dst[19] = 0;
443 dst[18] = 1;
444 }
445
scale3(float m[],float s)446 static void scale3(float m[], float s) {
447 for (int i = 0; i < 3; ++i) {
448 m[i] *= s;
449 }
450 }
451
452 namespace {
453 enum Range { kFull, kLimited };
454 struct YUVCoeff {
455 float Kr, Kb;
456 int bits;
457 Range range;
458 };
459
460 const YUVCoeff gCoeff[] = {
461 { 0.2990f, 0.1140f, 8, kFull }, // kJPEG_Full_SkYUVColorSpace
462 { 0.2990f, 0.1140f, 8, kLimited }, // kRec601_Limited_SkYUVColorSpace
463 { 0.2126f, 0.0722f, 8, kFull }, // kRec709_Full_SkYUVColorSpace
464 { 0.2126f, 0.0722f, 8, kLimited }, // kRec709_Limited_SkYUVColorSpace
465 { 0.2627f, 0.0593f, 8, kFull }, // kBT2020_8bit_Full_SkYUVColorSpace
466 { 0.2627f, 0.0593f, 8, kLimited }, // kBT2020_8bit_Limited_SkYUVColorSpace
467 { 0.2627f, 0.0593f, 10, kFull }, // kBT2020_10bit_Full_SkYUVColorSpace
468 { 0.2627f, 0.0593f, 10, kLimited }, // kBT2020_10bit_Limited_SkYUVColorSpace
469 { 0.2627f, 0.0593f, 12, kFull }, // kBT2020_12bit_Full_SkYUVColorSpace
470 { 0.2627f, 0.0593f, 12, kLimited }, // kBT2020_12bit_Limited_SkYUVColorSpace
471 { 0.3000f, 0.1100f, 8, kFull }, // kFCC_Full_SkYUVColorSpace
472 { 0.3000f, 0.1100f, 8, kLimited }, // kFCC_Limited_SkYUVColorSpace
473 { 0.2120f, 0.0870f, 8, kFull }, // kSMPTE240_Full_SkYUVColorSpace
474 { 0.2120f, 0.0870f, 8, kLimited }, // kSMPTE240_Limited_SkYUVColorSpace
475 };
476 } // namespace
477
make_rgb_to_yuv_matrix_ycbcr(float mx[20],const YUVCoeff & c)478 static void make_rgb_to_yuv_matrix_ycbcr(float mx[20], const YUVCoeff& c) {
479 SkASSERT(c.bits >= 8);
480 const float Kr = c.Kr;
481 const float Kb = c.Kb;
482 const float Kg = 1.0f - Kr - Kb;
483 const float Cr = 0.5f / (1.0f - Kb);
484 const float Cb = 0.5f / (1.0f - Kr);
485
486 const int shift = c.bits - 8;
487
488 const float denom = static_cast<float>((1 << c.bits) - 1);
489 float scaleY = 1.0f,
490 addY = 0.0f,
491 scaleUV = 1.0f,
492 addUV = (128 << shift) / denom;
493
494 if (c.range == kLimited) {
495 scaleY = (219 << shift) / denom;
496 addY = ( 16 << shift) / denom;
497 scaleUV = (224 << shift) / denom;
498 }
499
500 float m[20] = {
501 Kr, Kg, Kb, 0, addY,
502 -Kr, -Kg, 1-Kb, 0, addUV,
503 1-Kr, -Kg, -Kb, 0, addUV,
504 0, 0, 0, 1, 0,
505 };
506 memcpy(mx, m, sizeof(m));
507 scale3(mx + 0, scaleY );
508 scale3(mx + 5, Cr * scaleUV);
509 scale3(mx + 10, Cb * scaleUV);
510 }
511
make_rgb_to_yuv_matrix_ydzdx(float mx[20],Range range)512 static void make_rgb_to_yuv_matrix_ydzdx(float mx[20], Range range) {
513 const int bits = 8;
514 const float denom = static_cast<float>((1 << bits) - 1);
515 float scaleY = 1.0f,
516 addY = 0.0f,
517 scaleUV = 1.0f,
518 addUV = 128 / denom;
519
520 if (range == kLimited) {
521 scaleY = 219 / denom;
522 addY = 16 / denom;
523 scaleUV = 224 / denom;
524 }
525
526 // YDZDX applies range correction to YUV values similar to YCbCr.
527 float m[20] = {
528 0.0f, 1.0f, 0.0f, 0.0f, addY, // Y
529 0.0f, -0.5f, 0.986566f / 2.0f, 0.0f, addUV, // DX or DZ
530 0.5f, -0.991902f / 2.0f, 0.0f, 0.0f, addUV, // DZ or DX
531 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
532 };
533 memcpy(mx, m, sizeof(m));
534 scale3(mx + 0, scaleY );
535 scale3(mx + 5, scaleUV);
536 scale3(mx + 10, scaleUV);
537 }
538
make_rgb_to_yuv_matrix_gbr(float mx[20],Range range)539 static void make_rgb_to_yuv_matrix_gbr(float mx[20], Range range) {
540 const int bits = 8;
541 const float denom = static_cast<float>((1 << bits) - 1);
542 float scaleY = 1.0f,
543 addY = 0.0f;
544
545 if (range == kLimited) {
546 scaleY = 219 / denom;
547 addY = 16 / denom;
548 }
549
550 // GBR applies range correction to RGB values similar to YCgCo.
551 float m[20] = {
552 0.0f, 1.0f, 0.0f, 0.0f, addY, // G
553 0.0f, 0.0f, 1.0f, 0.0f, addY, // B
554 1.0f, 0.0f, 0.0f, 0.0f, addY, // R
555 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
556 };
557 memcpy(mx, m, sizeof(m));
558 scale3(mx + 0, scaleY);
559 scale3(mx + 5, scaleY);
560 scale3(mx + 10, scaleY);
561 }
562
make_rgb_to_yuv_matrix_ycgco(float mx[20],int bits,Range range)563 static void make_rgb_to_yuv_matrix_ycgco(float mx[20], int bits, Range range) {
564 SkASSERT(bits >= 8);
565 const int shift = bits - 8;
566 const float denom = static_cast<float>((1 << bits) - 1);
567 float scaleY = 1.0f,
568 addY = 0.0f,
569 chroma05 = static_cast<float>(1 << (bits - 1)) / denom;
570
571 if (range == kLimited) {
572 scaleY = (219 << shift) / denom;
573 addY = ( 16 << shift) / denom;
574 }
575
576 float m[20] = {
577 0.25f, 0.5f, 0.25f, 0.0f, addY,
578 -0.25f, 0.5f, -0.25f, 0.0f, chroma05,
579 0.5f, 0.0f, -0.5f, 0.0f, chroma05,
580 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
581 };
582 memcpy(mx, m, sizeof(m));
583 scale3(mx + 0, scaleY);
584 scale3(mx + 5, scaleY);
585 scale3(mx + 10, scaleY);
586 }
587
make_rgb_to_yuv_matrix(float mx[20],SkYUVColorSpace cs)588 static void make_rgb_to_yuv_matrix(float mx[20], SkYUVColorSpace cs) {
589 switch (cs) {
590 case kJPEG_Full_SkYUVColorSpace:
591 case kRec601_Limited_SkYUVColorSpace:
592 case kRec709_Full_SkYUVColorSpace:
593 case kRec709_Limited_SkYUVColorSpace:
594 case kBT2020_8bit_Full_SkYUVColorSpace:
595 case kBT2020_8bit_Limited_SkYUVColorSpace:
596 case kBT2020_10bit_Full_SkYUVColorSpace:
597 case kBT2020_10bit_Limited_SkYUVColorSpace:
598 case kBT2020_12bit_Full_SkYUVColorSpace:
599 case kBT2020_12bit_Limited_SkYUVColorSpace:
600 case kFCC_Full_SkYUVColorSpace:
601 case kFCC_Limited_SkYUVColorSpace:
602 case kSMPTE240_Full_SkYUVColorSpace:
603 case kSMPTE240_Limited_SkYUVColorSpace:
604 case kIdentity_SkYUVColorSpace:
605 return make_rgb_to_yuv_matrix_ycbcr(mx, gCoeff[(unsigned)cs]);
606 case kYDZDX_Full_SkYUVColorSpace:
607 return make_rgb_to_yuv_matrix_ydzdx(mx, Range::kFull);
608 case kYDZDX_Limited_SkYUVColorSpace:
609 return make_rgb_to_yuv_matrix_ydzdx(mx, Range::kLimited);
610 case kGBR_Full_SkYUVColorSpace:
611 return make_rgb_to_yuv_matrix_gbr(mx, Range::kFull);
612 case kGBR_Limited_SkYUVColorSpace:
613 return make_rgb_to_yuv_matrix_gbr(mx, Range::kLimited);
614 case kYCgCo_8bit_Full_SkYUVColorSpace:
615 return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/8, Range::kFull);
616 case kYCgCo_8bit_Limited_SkYUVColorSpace:
617 return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/8, Range::kLimited);
618 case kYCgCo_10bit_Full_SkYUVColorSpace:
619 return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/10, Range::kFull);
620 case kYCgCo_10bit_Limited_SkYUVColorSpace:
621 return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/10, Range::kLimited);
622 case kYCgCo_12bit_Full_SkYUVColorSpace:
623 return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/12, Range::kFull);
624 case kYCgCo_12bit_Limited_SkYUVColorSpace:
625 return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/12, Range::kLimited);
626 }
627 }
628
dump(const float m[20],SkYUVColorSpace cs,bool rgb2yuv)629 static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv) {
630 const char* names[] = {
631 "JPEG_full",
632 "Rec601_limited",
633 "Rec709_full",
634 "Rec709_limited",
635 "BT2020_8bit_full",
636 "BT2020_8bit_limited",
637 "BT2020_10bit_full",
638 "BT2020_10bit_limited",
639 "BT2020_12bit_full",
640 "BT2020_12bit_limited",
641 "FCC_full",
642 "FCC_limited",
643 "SMPTE240_full",
644 "SMPTE240_limited",
645 "YDZDX_full",
646 "YDZDX_limited",
647 "GBR_full",
648 "GBR_limited",
649 "YCgCo_8bit_full",
650 "YCgCo_8bit_limited",
651 "YCgCo_10bit_full",
652 "YCgCo_10bit_limited",
653 "YCgCo_12bit_full",
654 "YCgCo_12bit_limited",
655 };
656 const char* dirnames[] = {
657 "yuv_to_rgb", "rgb_to_yuv",
658 };
659 SkDebugf("const float %s_%s[] = {\n", names[cs], dirnames[rgb2yuv]);
660 for (int i = 0; i < 4; ++i) {
661 SkDebugf(" ");
662 for (int j = 0; j < 5; ++j) {
663 SkDebugf(" %9.6ff,", m[i * 5 + j]);
664 }
665 SkDebugf("\n");
666 }
667 SkDebugf("};\n");
668 }
669
670 // Used to create the prebuilt tables for each colorspace.
671 // Don't remove this function, in case we want to recompute those tables in the future.
SkColorMatrix_DumpYUVMatrixTables()672 void SkColorMatrix_DumpYUVMatrixTables() {
673 for (int i = 0; i < kLastEnum_SkYUVColorSpace; ++i) {
674 SkYUVColorSpace cs = static_cast<SkYUVColorSpace>(i);
675 float m[20];
676 make_rgb_to_yuv_matrix(m, cs);
677 dump(m, cs, true);
678 SkM44 m44, im44;
679 colormatrix_to_matrix44(m, &m44);
680 float im[20];
681 #ifdef SK_DEBUG
682 // be sure our coversion between matrix44 and colormatrix is perfect
683 matrix44_to_colormatrix(m44, im);
684 SkASSERT(memcmp(m, im, sizeof(im)) == 0);
685 #endif
686 SkAssertResult(m44.invert(&im44));
687 matrix44_to_colormatrix(im44, im);
688 dump(im, cs, false);
689 }
690 }
691