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 BT2020_16bit_full_rgb_to_yuv[] = {
140 0.262700f, 0.678000f, 0.059300f, 0.000000f, 0.000000f,
141 -0.139630f, -0.360370f, 0.500000f, 0.000000f, 0.500008f,
142 0.500000f, -0.459786f, -0.040214f, 0.000000f, 0.500008f,
143 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
144 };
145 const float BT2020_16bit_full_yuv_to_rgb[] = {
146 1.000000f, -0.000000f, 1.474600f, 0.000000f, -0.737311f,
147 1.000000f, -0.164553f, -0.571353f, 0.000000f, 0.367959f,
148 1.000000f, 1.881400f, -0.000000f, 0.000000f, -0.940714f,
149 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
150 };
151 const float BT2020_16bit_limited_rgb_to_yuv[] = {
152 0.224735f, 0.580017f, 0.050730f, 0.000000f, 0.062501f,
153 -0.122178f, -0.315329f, 0.437507f, 0.000000f, 0.500008f,
154 0.437507f, -0.402319f, -0.035188f, 0.000000f, 0.500008f,
155 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
156 };
157 const float BT2020_16bit_limited_yuv_to_rgb[] = {
158 1.168932f, 0.000000f, 1.685231f, 0.000000f, -0.915688f,
159 1.168932f, -0.188058f, -0.652965f, 0.000000f, 0.347458f,
160 1.168932f, 2.150139f, -0.000000f, 0.000000f, -1.148145f,
161 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
162 };
163 const float FCC_full_rgb_to_yuv[] = {
164 0.300000f, 0.590000f, 0.110000f, 0.000000f, 0.000000f,
165 -0.168539f, -0.331461f, 0.500000f, 0.000000f, 0.501961f,
166 0.500000f, -0.421429f, -0.078571f, 0.000000f, 0.501961f,
167 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
168 };
169 const float FCC_full_yuv_to_rgb[] = {
170 1.000000f, 0.000000f, 1.400000f, 0.000000f, -0.702745f,
171 1.000000f, -0.331864f, -0.711864f, 0.000000f, 0.523911f,
172 1.000000f, 1.780000f, 0.000000f, 0.000000f, -0.893490f,
173 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
174 };
175 const float FCC_limited_rgb_to_yuv[] = {
176 0.257647f, 0.506706f, 0.094471f, 0.000000f, 0.062745f,
177 -0.148050f, -0.291165f, 0.439216f, 0.000000f, 0.501961f,
178 0.439216f, -0.370196f, -0.069020f, 0.000000f, 0.501961f,
179 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
180 };
181 const float FCC_limited_yuv_to_rgb[] = {
182 1.164384f, -0.000000f, 1.593750f, 0.000000f, -0.873059f,
183 1.164384f, -0.377792f, -0.810381f, 0.000000f, 0.523357f,
184 1.164384f, 2.026339f, 0.000000f, 0.000000f, -1.090202f,
185 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
186 };
187 const float SMPTE240_full_rgb_to_yuv[] = {
188 0.212000f, 0.701000f, 0.087000f, 0.000000f, 0.000000f,
189 -0.116101f, -0.383899f, 0.500000f, 0.000000f, 0.501961f,
190 0.500000f, -0.444797f, -0.055203f, 0.000000f, 0.501961f,
191 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
192 };
193 const float SMPTE240_full_yuv_to_rgb[] = {
194 1.000000f, 0.000000f, 1.576000f, 0.000000f, -0.791090f,
195 1.000000f, -0.226622f, -0.476622f, 0.000000f, 0.353001f,
196 1.000000f, 1.826000f, 0.000000f, 0.000000f, -0.916580f,
197 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
198 };
199 const float SMPTE240_limited_rgb_to_yuv[] = {
200 0.182071f, 0.602035f, 0.074718f, 0.000000f, 0.062745f,
201 -0.101987f, -0.337229f, 0.439216f, 0.000000f, 0.501961f,
202 0.439216f, -0.390724f, -0.048492f, 0.000000f, 0.501961f,
203 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
204 };
205 const float SMPTE240_limited_yuv_to_rgb[] = {
206 1.164384f, -0.000000f, 1.794107f, 0.000000f, -0.973631f,
207 1.164384f, -0.257985f, -0.542583f, 0.000000f, 0.328794f,
208 1.164384f, 2.078705f, 0.000000f, 0.000000f, -1.116488f,
209 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
210 };
211 const float YDZDX_full_rgb_to_yuv[] = {
212 0.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f,
213 0.000000f, -0.500000f, 0.493283f, 0.000000f, 0.501961f,
214 0.500000f, -0.495951f, 0.000000f, 0.000000f, 0.501961f,
215 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
216 };
217 const float YDZDX_full_yuv_to_rgb[] = {
218 0.991902f, -0.000000f, 2.000000f, 0.000000f, -1.003922f,
219 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
220 1.013617f, 2.027234f, 0.000000f, 0.000000f, -1.017592f,
221 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
222 };
223 const float YDZDX_limited_rgb_to_yuv[] = {
224 0.000000f, 0.858824f, 0.000000f, 0.000000f, 0.062745f,
225 0.000000f, -0.439216f, 0.433315f, 0.000000f, 0.501961f,
226 0.439216f, -0.435659f, 0.000000f, 0.000000f, 0.501961f,
227 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
228 };
229 const float YDZDX_limited_yuv_to_rgb[] = {
230 1.154954f, -0.000000f, 2.276786f, 0.000000f, -1.215325f,
231 1.164384f, 0.000000f, 0.000000f, 0.000000f, -0.073059f,
232 1.180239f, 2.307788f, 0.000000f, 0.000000f, -1.232474f,
233 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
234 };
235 const float GBR_full_rgb_to_yuv[] = {
236 0.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f,
237 0.000000f, 0.000000f, 1.000000f, 0.000000f, 0.000000f,
238 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
239 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
240 };
241 const float GBR_full_yuv_to_rgb[] = {
242 0.000000f, 0.000000f, 1.000000f, 0.000000f, 0.000000f,
243 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
244 0.000000f, 1.000000f, 0.000000f, 0.000000f, -0.000000f,
245 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
246 };
247 const float GBR_limited_rgb_to_yuv[] = {
248 0.000000f, 0.858824f, 0.000000f, 0.000000f, 0.062745f,
249 0.000000f, 0.000000f, 0.858824f, 0.000000f, 0.062745f,
250 0.858824f, 0.000000f, 0.000000f, 0.000000f, 0.062745f,
251 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
252 };
253 const float GBR_limited_yuv_to_rgb[] = {
254 0.000000f, 0.000000f, 1.164384f, 0.000000f, -0.073059f,
255 1.164384f, 0.000000f, 0.000000f, 0.000000f, -0.073059f,
256 0.000000f, 1.164384f, 0.000000f, 0.000000f, -0.073059f,
257 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
258 };
259 const float YCgCo_8bit_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.501961f,
262 0.500000f, 0.000000f, -0.500000f, 0.000000f, 0.501961f,
263 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
264 };
265 const float YCgCo_8bit_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.501961f,
268 1.000000f, -1.000000f, -1.000000f, 0.000000f, 1.003922f,
269 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
270 };
271 const float YCgCo_8bit_limited_rgb_to_yuv[] = {
272 0.214706f, 0.429412f, 0.214706f, 0.000000f, 0.062745f,
273 -0.214706f, 0.429412f, -0.214706f, 0.000000f, 0.501961f,
274 0.429412f, 0.000000f, -0.429412f, 0.000000f, 0.501961f,
275 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
276 };
277 const float YCgCo_8bit_limited_yuv_to_rgb[] = {
278 1.164384f, -1.164384f, 1.164384f, 0.000000f, -0.073059f,
279 1.164384f, 1.164384f, 0.000000f, 0.000000f, -0.657534f,
280 1.164384f, -1.164384f, -1.164384f, 0.000000f, 1.095891f,
281 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
282 };
283 const float YCgCo_10bit_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.500489f,
286 0.500000f, 0.000000f, -0.500000f, 0.000000f, 0.500489f,
287 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
288 };
289 const float YCgCo_10bit_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.500489f,
292 1.000000f, -1.000000f, -1.000000f, 0.000000f, 1.000978f,
293 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
294 };
295 const float YCgCo_10bit_limited_rgb_to_yuv[] = {
296 0.214076f, 0.428153f, 0.214076f, 0.000000f, 0.062561f,
297 -0.214076f, 0.428153f, -0.214076f, 0.000000f, 0.500489f,
298 0.428153f, 0.000000f, -0.428153f, 0.000000f, 0.500489f,
299 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
300 };
301 const float YCgCo_10bit_limited_yuv_to_rgb[] = {
302 1.167808f, -1.167808f, 1.167808f, 0.000000f, -0.073059f,
303 1.167808f, 1.167808f, 0.000000f, 0.000000f, -0.657534f,
304 1.167808f, -1.167808f, -1.167808f, 0.000000f, 1.095890f,
305 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
306 };
307 const float YCgCo_12bit_full_rgb_to_yuv[] = {
308 0.250000f, 0.500000f, 0.250000f, 0.000000f, 0.000000f,
309 -0.250000f, 0.500000f, -0.250000f, 0.000000f, 0.500122f,
310 0.500000f, 0.000000f, -0.500000f, 0.000000f, 0.500122f,
311 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
312 };
313 const float YCgCo_12bit_full_yuv_to_rgb[] = {
314 1.000000f, -1.000000f, 1.000000f, 0.000000f, 0.000000f,
315 1.000000f, 1.000000f, 0.000000f, 0.000000f, -0.500122f,
316 1.000000f, -1.000000f, -1.000000f, 0.000000f, 1.000244f,
317 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
318 };
319 const float YCgCo_12bit_limited_rgb_to_yuv[] = {
320 0.213919f, 0.427839f, 0.213919f, 0.000000f, 0.062515f,
321 -0.213919f, 0.427839f, -0.213919f, 0.000000f, 0.500122f,
322 0.427839f, 0.000000f, -0.427839f, 0.000000f, 0.500122f,
323 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
324 };
325 const float YCgCo_12bit_limited_yuv_to_rgb[] = {
326 1.168664f, -1.168664f, 1.168664f, 0.000000f, -0.073059f,
327 1.168664f, 1.168664f, 0.000000f, 0.000000f, -0.657534f,
328 1.168664f, -1.168664f, -1.168664f, 0.000000f, 1.095891f,
329 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
330 };
331 const float YCgCo_16bit_full_rgb_to_yuv[] = {
332 0.250000f, 0.500000f, 0.250000f, 0.000000f, 0.000000f,
333 -0.250000f, 0.500000f, -0.250000f, 0.000000f, 0.500008f,
334 0.500000f, 0.000000f, -0.500000f, 0.000000f, 0.500008f,
335 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
336 };
337 const float YCgCo_16bit_full_yuv_to_rgb[] = {
338 1.000000f, -1.000000f, 1.000000f, 0.000000f, 0.000000f,
339 1.000000f, 1.000000f, 0.000000f, 0.000000f, -0.500008f,
340 1.000000f, -1.000000f, -1.000000f, 0.000000f, 1.000015f,
341 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
342 };
343 const float YCgCo_16bit_limited_rgb_to_yuv[] = {
344 0.213870f, 0.427741f, 0.213870f, 0.000000f, 0.062501f,
345 -0.213870f, 0.427741f, -0.213870f, 0.000000f, 0.500008f,
346 0.427741f, 0.000000f, -0.427741f, 0.000000f, 0.500008f,
347 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
348 };
349 const float YCgCo_16bit_limited_yuv_to_rgb[] = {
350 1.168932f, -1.168932f, 1.168932f, 0.000000f, -0.073059f,
351 1.168932f, 1.168932f, 0.000000f, 0.000000f, -0.657534f,
352 1.168932f, -1.168932f, -1.168932f, 0.000000f, 1.095890f,
353 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
354 };
355
356 static_assert(kJPEG_Full_SkYUVColorSpace == 0, "");
357 static_assert(kRec601_Limited_SkYUVColorSpace == 1, "");
358 static_assert(kRec709_Full_SkYUVColorSpace == 2, "");
359 static_assert(kRec709_Limited_SkYUVColorSpace == 3, "");
360 static_assert(kBT2020_8bit_Full_SkYUVColorSpace == 4, "");
361 static_assert(kBT2020_8bit_Limited_SkYUVColorSpace == 5, "");
362 static_assert(kBT2020_10bit_Full_SkYUVColorSpace == 6, "");
363 static_assert(kBT2020_10bit_Limited_SkYUVColorSpace == 7, "");
364 static_assert(kBT2020_12bit_Full_SkYUVColorSpace == 8, "");
365 static_assert(kBT2020_12bit_Limited_SkYUVColorSpace == 9, "");
366 static_assert(kBT2020_16bit_Full_SkYUVColorSpace == 10, "");
367 static_assert(kBT2020_16bit_Limited_SkYUVColorSpace == 11, "");
368 static_assert(kFCC_Full_SkYUVColorSpace == 12, "");
369 static_assert(kFCC_Limited_SkYUVColorSpace == 13, "");
370 static_assert(kSMPTE240_Full_SkYUVColorSpace == 14, "");
371 static_assert(kSMPTE240_Limited_SkYUVColorSpace == 15, "");
372 static_assert(kYDZDX_Full_SkYUVColorSpace == 16, "");
373 static_assert(kYDZDX_Limited_SkYUVColorSpace == 17, "");
374 static_assert(kGBR_Full_SkYUVColorSpace == 18, "");
375 static_assert(kGBR_Limited_SkYUVColorSpace == 19, "");
376 static_assert(kYCgCo_8bit_Full_SkYUVColorSpace == 20, "");
377 static_assert(kYCgCo_8bit_Limited_SkYUVColorSpace == 21, "");
378 static_assert(kYCgCo_10bit_Full_SkYUVColorSpace == 22, "");
379 static_assert(kYCgCo_10bit_Limited_SkYUVColorSpace == 23, "");
380 static_assert(kYCgCo_12bit_Full_SkYUVColorSpace == 24, "");
381 static_assert(kYCgCo_12bit_Limited_SkYUVColorSpace == 25, "");
382 static_assert(kYCgCo_16bit_Full_SkYUVColorSpace == 26, "");
383 static_assert(kYCgCo_16bit_Limited_SkYUVColorSpace == 27, "");
384
385 const float* yuv_to_rgb_array[] = {
386 JPEG_full_yuv_to_rgb,
387 Rec601_limited_yuv_to_rgb,
388 Rec709_full_yuv_to_rgb,
389 Rec709_limited_yuv_to_rgb,
390 BT2020_8bit_full_yuv_to_rgb,
391 BT2020_8bit_limited_yuv_to_rgb,
392 BT2020_10bit_full_yuv_to_rgb,
393 BT2020_10bit_limited_yuv_to_rgb,
394 BT2020_12bit_full_yuv_to_rgb,
395 BT2020_12bit_limited_yuv_to_rgb,
396 BT2020_16bit_full_yuv_to_rgb,
397 BT2020_16bit_limited_yuv_to_rgb,
398 FCC_full_yuv_to_rgb,
399 FCC_limited_yuv_to_rgb,
400 SMPTE240_full_yuv_to_rgb,
401 SMPTE240_limited_yuv_to_rgb,
402 YDZDX_full_yuv_to_rgb,
403 YDZDX_limited_yuv_to_rgb,
404 GBR_full_yuv_to_rgb,
405 GBR_limited_yuv_to_rgb,
406 YCgCo_8bit_full_yuv_to_rgb,
407 YCgCo_8bit_limited_yuv_to_rgb,
408 YCgCo_10bit_full_yuv_to_rgb,
409 YCgCo_10bit_limited_yuv_to_rgb,
410 YCgCo_12bit_full_yuv_to_rgb,
411 YCgCo_12bit_limited_yuv_to_rgb,
412 YCgCo_16bit_full_yuv_to_rgb,
413 YCgCo_16bit_limited_yuv_to_rgb,
414 };
415
416 const float* rgb_to_yuv_array[] = {
417 JPEG_full_rgb_to_yuv,
418 Rec601_limited_rgb_to_yuv,
419 Rec709_full_rgb_to_yuv,
420 Rec709_limited_rgb_to_yuv,
421 BT2020_8bit_full_rgb_to_yuv,
422 BT2020_8bit_limited_rgb_to_yuv,
423 BT2020_10bit_full_rgb_to_yuv,
424 BT2020_10bit_limited_rgb_to_yuv,
425 BT2020_12bit_full_rgb_to_yuv,
426 BT2020_12bit_limited_rgb_to_yuv,
427 BT2020_16bit_full_rgb_to_yuv,
428 BT2020_16bit_limited_rgb_to_yuv,
429 FCC_full_rgb_to_yuv,
430 FCC_limited_rgb_to_yuv,
431 SMPTE240_full_rgb_to_yuv,
432 SMPTE240_limited_rgb_to_yuv,
433 YDZDX_full_rgb_to_yuv,
434 YDZDX_limited_rgb_to_yuv,
435 GBR_full_rgb_to_yuv,
436 GBR_limited_rgb_to_yuv,
437 YCgCo_8bit_full_rgb_to_yuv,
438 YCgCo_8bit_limited_rgb_to_yuv,
439 YCgCo_10bit_full_rgb_to_yuv,
440 YCgCo_10bit_limited_rgb_to_yuv,
441 YCgCo_12bit_full_rgb_to_yuv,
442 YCgCo_12bit_limited_rgb_to_yuv,
443 YCgCo_16bit_full_rgb_to_yuv,
444 YCgCo_16bit_limited_rgb_to_yuv,
445 };
446
447 constexpr size_t kSizeOfColorMatrix = 20 * sizeof(float);
448
SkColorMatrix_RGB2YUV(SkYUVColorSpace cs,float m[20])449 void SkColorMatrix_RGB2YUV(SkYUVColorSpace cs, float m[20]) {
450 if ((unsigned)cs < (unsigned)kIdentity_SkYUVColorSpace) {
451 memcpy(m, rgb_to_yuv_array[(unsigned)cs], kSizeOfColorMatrix);
452 } else {
453 memset(m, 0, kSizeOfColorMatrix);
454 m[0] = m[6] = m[12] = m[18] = 1;
455 }
456 }
457
SkColorMatrix_YUV2RGB(SkYUVColorSpace cs,float m[20])458 void SkColorMatrix_YUV2RGB(SkYUVColorSpace cs, float m[20]) {
459 if ((unsigned)cs < (unsigned)kIdentity_SkYUVColorSpace) {
460 memcpy(m, yuv_to_rgb_array[(unsigned)cs], kSizeOfColorMatrix);
461 } else {
462 memset(m, 0, kSizeOfColorMatrix);
463 m[0] = m[6] = m[12] = m[18] = 1;
464 }
465 }
466
467 ///////////////////////////////////////////////////////////////////////////////////////////////////
468
469 // we just drop the alpha rol/col from the colormatrix
470 // output is | tr |
471 // | 3x3 tg |
472 // | tb |
473 // | 0 0 0 1 |
colormatrix_to_matrix44(const float src[20],SkM44 * dst)474 static void colormatrix_to_matrix44(const float src[20], SkM44* dst) {
475 *dst = SkM44(src[ 0], src[ 1], src[ 2], src[ 4],
476 src[ 5], src[ 6], src[ 7], src[ 9],
477 src[10], src[11], src[12], src[14],
478 0, 0, 0, 1);
479 }
480
481 // input: ignore the bottom row
482 // output: inject identity row/column for alpha
matrix44_to_colormatrix(const SkM44 & src,float dst[20])483 static void matrix44_to_colormatrix(const SkM44& src, float dst[20]) {
484 dst[0] = src.rc(0,0);
485 dst[1] = src.rc(0,1);
486 dst[2] = src.rc(0,2);
487 dst[3] = 0;
488 dst[4] = src.rc(0,3); // tx
489
490 dst[5] = src.rc(1,0);
491 dst[6] = src.rc(1,1);
492 dst[7] = src.rc(1,2);
493 dst[8] = 0;
494 dst[9] = src.rc(1,3); // ty
495
496 dst[10] = src.rc(2,0);
497 dst[11] = src.rc(2,1);
498 dst[12] = src.rc(2,2);
499 dst[13] = 0;
500 dst[14] = src.rc(2,3); // tz
501
502 dst[15] = dst[16] = dst[17] = dst[19] = 0;
503 dst[18] = 1;
504 }
505
scale3(float m[],float s)506 static void scale3(float m[], float s) {
507 for (int i = 0; i < 3; ++i) {
508 m[i] *= s;
509 }
510 }
511
512 namespace {
513 enum Range { kFull, kLimited };
514 struct YUVCoeff {
515 float Kr, Kb;
516 int bits;
517 Range range;
518 };
519
520 const YUVCoeff gCoeff[] = {
521 { 0.2990f, 0.1140f, 8, kFull }, // kJPEG_Full_SkYUVColorSpace
522 { 0.2990f, 0.1140f, 8, kLimited }, // kRec601_Limited_SkYUVColorSpace
523 { 0.2126f, 0.0722f, 8, kFull }, // kRec709_Full_SkYUVColorSpace
524 { 0.2126f, 0.0722f, 8, kLimited }, // kRec709_Limited_SkYUVColorSpace
525 { 0.2627f, 0.0593f, 8, kFull }, // kBT2020_8bit_Full_SkYUVColorSpace
526 { 0.2627f, 0.0593f, 8, kLimited }, // kBT2020_8bit_Limited_SkYUVColorSpace
527 { 0.2627f, 0.0593f, 10, kFull }, // kBT2020_10bit_Full_SkYUVColorSpace
528 { 0.2627f, 0.0593f, 10, kLimited }, // kBT2020_10bit_Limited_SkYUVColorSpace
529 { 0.2627f, 0.0593f, 12, kFull }, // kBT2020_12bit_Full_SkYUVColorSpace
530 { 0.2627f, 0.0593f, 12, kLimited }, // kBT2020_12bit_Limited_SkYUVColorSpace
531 { 0.2627f, 0.0593f, 16, kFull }, // kBT2020_16bit_Full_SkYUVColorSpace
532 { 0.2627f, 0.0593f, 16, kLimited }, // kBT2020_16bit_Limited_SkYUVColorSpace
533 { 0.3000f, 0.1100f, 8, kFull }, // kFCC_Full_SkYUVColorSpace
534 { 0.3000f, 0.1100f, 8, kLimited }, // kFCC_Limited_SkYUVColorSpace
535 { 0.2120f, 0.0870f, 8, kFull }, // kSMPTE240_Full_SkYUVColorSpace
536 { 0.2120f, 0.0870f, 8, kLimited }, // kSMPTE240_Limited_SkYUVColorSpace
537 };
538 } // namespace
539
make_rgb_to_yuv_matrix_ycbcr(float mx[20],const YUVCoeff & c)540 static void make_rgb_to_yuv_matrix_ycbcr(float mx[20], const YUVCoeff& c) {
541 SkASSERT(c.bits >= 8);
542 const float Kr = c.Kr;
543 const float Kb = c.Kb;
544 const float Kg = 1.0f - Kr - Kb;
545 const float Cr = 0.5f / (1.0f - Kb);
546 const float Cb = 0.5f / (1.0f - Kr);
547
548 const int shift = c.bits - 8;
549
550 const float denom = static_cast<float>((1 << c.bits) - 1);
551 float scaleY = 1.0f,
552 addY = 0.0f,
553 scaleUV = 1.0f,
554 addUV = (128 << shift) / denom;
555
556 if (c.range == kLimited) {
557 scaleY = (219 << shift) / denom;
558 addY = ( 16 << shift) / denom;
559 scaleUV = (224 << shift) / denom;
560 }
561
562 float m[20] = {
563 Kr, Kg, Kb, 0, addY,
564 -Kr, -Kg, 1-Kb, 0, addUV,
565 1-Kr, -Kg, -Kb, 0, addUV,
566 0, 0, 0, 1, 0,
567 };
568 memcpy(mx, m, sizeof(m));
569 scale3(mx + 0, scaleY );
570 scale3(mx + 5, Cr * scaleUV);
571 scale3(mx + 10, Cb * scaleUV);
572 }
573
make_rgb_to_yuv_matrix_ydzdx(float mx[20],Range range)574 static void make_rgb_to_yuv_matrix_ydzdx(float mx[20], Range range) {
575 const int bits = 8;
576 const float denom = static_cast<float>((1 << bits) - 1);
577 float scaleY = 1.0f,
578 addY = 0.0f,
579 scaleUV = 1.0f,
580 addUV = 128 / denom;
581
582 if (range == kLimited) {
583 scaleY = 219 / denom;
584 addY = 16 / denom;
585 scaleUV = 224 / denom;
586 }
587
588 // YDZDX applies range correction to YUV values similar to YCbCr.
589 float m[20] = {
590 0.0f, 1.0f, 0.0f, 0.0f, addY, // Y
591 0.0f, -0.5f, 0.986566f / 2.0f, 0.0f, addUV, // DX or DZ
592 0.5f, -0.991902f / 2.0f, 0.0f, 0.0f, addUV, // DZ or DX
593 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
594 };
595 memcpy(mx, m, sizeof(m));
596 scale3(mx + 0, scaleY );
597 scale3(mx + 5, scaleUV);
598 scale3(mx + 10, scaleUV);
599 }
600
make_rgb_to_yuv_matrix_gbr(float mx[20],Range range)601 static void make_rgb_to_yuv_matrix_gbr(float mx[20], Range range) {
602 const int bits = 8;
603 const float denom = static_cast<float>((1 << bits) - 1);
604 float scaleY = 1.0f,
605 addY = 0.0f;
606
607 if (range == kLimited) {
608 scaleY = 219 / denom;
609 addY = 16 / denom;
610 }
611
612 // GBR applies range correction to RGB values similar to YCgCo.
613 float m[20] = {
614 0.0f, 1.0f, 0.0f, 0.0f, addY, // G
615 0.0f, 0.0f, 1.0f, 0.0f, addY, // B
616 1.0f, 0.0f, 0.0f, 0.0f, addY, // R
617 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
618 };
619 memcpy(mx, m, sizeof(m));
620 scale3(mx + 0, scaleY);
621 scale3(mx + 5, scaleY);
622 scale3(mx + 10, scaleY);
623 }
624
make_rgb_to_yuv_matrix_ycgco(float mx[20],int bits,Range range)625 static void make_rgb_to_yuv_matrix_ycgco(float mx[20], int bits, Range range) {
626 SkASSERT(bits >= 8);
627 const int shift = bits - 8;
628 const float denom = static_cast<float>((1 << bits) - 1);
629 float scaleY = 1.0f,
630 addY = 0.0f,
631 chroma05 = static_cast<float>(1 << (bits - 1)) / denom;
632
633 if (range == kLimited) {
634 scaleY = (219 << shift) / denom;
635 addY = ( 16 << shift) / denom;
636 }
637
638 float m[20] = {
639 0.25f, 0.5f, 0.25f, 0.0f, addY,
640 -0.25f, 0.5f, -0.25f, 0.0f, chroma05,
641 0.5f, 0.0f, -0.5f, 0.0f, chroma05,
642 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
643 };
644 memcpy(mx, m, sizeof(m));
645 scale3(mx + 0, scaleY);
646 scale3(mx + 5, scaleY);
647 scale3(mx + 10, scaleY);
648 }
649
make_rgb_to_yuv_matrix(float mx[20],SkYUVColorSpace cs)650 static void make_rgb_to_yuv_matrix(float mx[20], SkYUVColorSpace cs) {
651 switch (cs) {
652 case kJPEG_Full_SkYUVColorSpace:
653 case kRec601_Limited_SkYUVColorSpace:
654 case kRec709_Full_SkYUVColorSpace:
655 case kRec709_Limited_SkYUVColorSpace:
656 case kBT2020_8bit_Full_SkYUVColorSpace:
657 case kBT2020_8bit_Limited_SkYUVColorSpace:
658 case kBT2020_10bit_Full_SkYUVColorSpace:
659 case kBT2020_10bit_Limited_SkYUVColorSpace:
660 case kBT2020_12bit_Full_SkYUVColorSpace:
661 case kBT2020_12bit_Limited_SkYUVColorSpace:
662 case kBT2020_16bit_Full_SkYUVColorSpace:
663 case kBT2020_16bit_Limited_SkYUVColorSpace:
664 case kFCC_Full_SkYUVColorSpace:
665 case kFCC_Limited_SkYUVColorSpace:
666 case kSMPTE240_Full_SkYUVColorSpace:
667 case kSMPTE240_Limited_SkYUVColorSpace:
668 case kIdentity_SkYUVColorSpace:
669 return make_rgb_to_yuv_matrix_ycbcr(mx, gCoeff[(unsigned)cs]);
670 case kYDZDX_Full_SkYUVColorSpace:
671 return make_rgb_to_yuv_matrix_ydzdx(mx, Range::kFull);
672 case kYDZDX_Limited_SkYUVColorSpace:
673 return make_rgb_to_yuv_matrix_ydzdx(mx, Range::kLimited);
674 case kGBR_Full_SkYUVColorSpace:
675 return make_rgb_to_yuv_matrix_gbr(mx, Range::kFull);
676 case kGBR_Limited_SkYUVColorSpace:
677 return make_rgb_to_yuv_matrix_gbr(mx, Range::kLimited);
678 case kYCgCo_8bit_Full_SkYUVColorSpace:
679 return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/8, Range::kFull);
680 case kYCgCo_8bit_Limited_SkYUVColorSpace:
681 return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/8, Range::kLimited);
682 case kYCgCo_10bit_Full_SkYUVColorSpace:
683 return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/10, Range::kFull);
684 case kYCgCo_10bit_Limited_SkYUVColorSpace:
685 return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/10, Range::kLimited);
686 case kYCgCo_12bit_Full_SkYUVColorSpace:
687 return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/12, Range::kFull);
688 case kYCgCo_12bit_Limited_SkYUVColorSpace:
689 return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/12, Range::kLimited);
690 case kYCgCo_16bit_Full_SkYUVColorSpace:
691 return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/16, Range::kFull);
692 case kYCgCo_16bit_Limited_SkYUVColorSpace:
693 return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/16, Range::kLimited);
694 }
695 }
696
dump(const float m[20],SkYUVColorSpace cs,bool rgb2yuv)697 static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv) {
698 const char* names[] = {
699 "JPEG_full",
700 "Rec601_limited",
701 "Rec709_full",
702 "Rec709_limited",
703 "BT2020_8bit_full",
704 "BT2020_8bit_limited",
705 "BT2020_10bit_full",
706 "BT2020_10bit_limited",
707 "BT2020_12bit_full",
708 "BT2020_12bit_limited",
709 "BT2020_16bit_full",
710 "BT2020_16bit_limited",
711 "FCC_full",
712 "FCC_limited",
713 "SMPTE240_full",
714 "SMPTE240_limited",
715 "YDZDX_full",
716 "YDZDX_limited",
717 "GBR_full",
718 "GBR_limited",
719 "YCgCo_8bit_full",
720 "YCgCo_8bit_limited",
721 "YCgCo_10bit_full",
722 "YCgCo_10bit_limited",
723 "YCgCo_12bit_full",
724 "YCgCo_12bit_limited",
725 "YCgCo_16bit_full",
726 "YCgCo_16bit_limited",
727 };
728 const char* dirnames[] = {
729 "yuv_to_rgb", "rgb_to_yuv",
730 };
731 SkDebugf("const float %s_%s[] = {\n", names[cs], dirnames[rgb2yuv]);
732 for (int i = 0; i < 4; ++i) {
733 SkDebugf(" ");
734 for (int j = 0; j < 5; ++j) {
735 SkDebugf(" %9.6ff,", m[i * 5 + j]);
736 }
737 SkDebugf("\n");
738 }
739 SkDebugf("};\n");
740 }
741
742 // Used to create the prebuilt tables for each colorspace.
743 // Don't remove this function, in case we want to recompute those tables in the future.
SkColorMatrix_DumpYUVMatrixTables()744 void SkColorMatrix_DumpYUVMatrixTables() {
745 for (int i = 0; i < kLastEnum_SkYUVColorSpace; ++i) {
746 SkYUVColorSpace cs = static_cast<SkYUVColorSpace>(i);
747 float m[20];
748 make_rgb_to_yuv_matrix(m, cs);
749 dump(m, cs, true);
750 SkM44 m44, im44;
751 colormatrix_to_matrix44(m, &m44);
752 float im[20];
753 #ifdef SK_DEBUG
754 // be sure our coversion between matrix44 and colormatrix is perfect
755 matrix44_to_colormatrix(m44, im);
756 SkASSERT(memcmp(m, im, sizeof(im)) == 0);
757 #endif
758 SkAssertResult(m44.invert(&im44));
759 matrix44_to_colormatrix(im44, im);
760 dump(im, cs, false);
761 }
762 }
763