Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/core/SkYUVMath.cpp
Line
Count
Source (jump to first uncovered line)
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 "include/core/SkM44.h"
9
#include "src/core/SkYUVMath.h"
10
11
// in SkColorMatrix order (row-major)
12
// Created by running SkColorMatrix_DumpYUVMatrixTables()
13
const float JPEG_full_rgb_to_yuv[] = {
14
      0.299000f,  0.587000f,  0.114000f,  0.000000f,  0.000000f,
15
     -0.168736f, -0.331264f,  0.500000f,  0.000000f,  0.501961f,
16
      0.500000f, -0.418688f, -0.081312f,  0.000000f,  0.501961f,
17
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
18
};
19
const float JPEG_full_yuv_to_rgb[] = {
20
      1.000000f, -0.000000f,  1.402000f,  0.000000f, -0.703749f,
21
      1.000000f, -0.344136f, -0.714136f,  0.000000f,  0.531211f,
22
      1.000000f,  1.772000f,  0.000000f,  0.000000f, -0.889475f,
23
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
24
};
25
const float Rec601_limited_rgb_to_yuv[] = {
26
      0.256788f,  0.504129f,  0.097906f,  0.000000f,  0.062745f,
27
     -0.148223f, -0.290993f,  0.439216f,  0.000000f,  0.501961f,
28
      0.439216f, -0.367788f, -0.071427f,  0.000000f,  0.501961f,
29
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
30
};
31
const float Rec601_limited_yuv_to_rgb[] = {
32
      1.164384f, -0.000000f,  1.596027f,  0.000000f, -0.874202f,
33
      1.164384f, -0.391762f, -0.812968f,  0.000000f,  0.531668f,
34
      1.164384f,  2.017232f,  0.000000f,  0.000000f, -1.085631f,
35
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
36
};
37
const float Rec709_full_rgb_to_yuv[] = {
38
      0.212600f,  0.715200f,  0.072200f,  0.000000f,  0.000000f,
39
     -0.114572f, -0.385428f,  0.500000f,  0.000000f,  0.501961f,
40
      0.500000f, -0.454153f, -0.045847f,  0.000000f,  0.501961f,
41
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
42
};
43
const float Rec709_full_yuv_to_rgb[] = {
44
      1.000000f, -0.000000f,  1.574800f,  0.000000f, -0.790488f,
45
      1.000000f, -0.187324f, -0.468124f,  0.000000f,  0.329010f,
46
      1.000000f,  1.855600f, -0.000000f,  0.000000f, -0.931439f,
47
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
48
};
49
const float Rec709_limited_rgb_to_yuv[] = {
50
      0.182586f,  0.614231f,  0.062007f,  0.000000f,  0.062745f,
51
     -0.100644f, -0.338572f,  0.439216f,  0.000000f,  0.501961f,
52
      0.439216f, -0.398942f, -0.040274f,  0.000000f,  0.501961f,
53
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
54
};
55
const float Rec709_limited_yuv_to_rgb[] = {
56
      1.164384f, -0.000000f,  1.792741f,  0.000000f, -0.972945f,
57
      1.164384f, -0.213249f, -0.532909f,  0.000000f,  0.301483f,
58
      1.164384f,  2.112402f, -0.000000f,  0.000000f, -1.133402f,
59
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
60
};
61
const float BT2020_8bit_full_rgb_to_yuv[] = {
62
      0.262700f,  0.678000f,  0.059300f,  0.000000f,  0.000000f,
63
     -0.139630f, -0.360370f,  0.500000f,  0.000000f,  0.501961f,
64
      0.500000f, -0.459786f, -0.040214f,  0.000000f,  0.501961f,
65
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
66
};
67
const float BT2020_8bit_full_yuv_to_rgb[] = {
68
      1.000000f, -0.000000f,  1.474600f,  0.000000f, -0.740191f,
69
      1.000000f, -0.164553f, -0.571353f,  0.000000f,  0.369396f,
70
      1.000000f,  1.881400f, -0.000000f,  0.000000f, -0.944389f,
71
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
72
};
73
const float BT2020_8bit_limited_rgb_to_yuv[] = {
74
      0.225613f,  0.582282f,  0.050928f,  0.000000f,  0.062745f,
75
     -0.122655f, -0.316560f,  0.439216f,  0.000000f,  0.501961f,
76
      0.439216f, -0.403890f, -0.035326f,  0.000000f,  0.501961f,
77
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
78
};
79
const float BT2020_8bit_limited_yuv_to_rgb[] = {
80
      1.164384f, -0.000000f,  1.678674f,  0.000000f, -0.915688f,
81
      1.164384f, -0.187326f, -0.650424f,  0.000000f,  0.347458f,
82
      1.164384f,  2.141772f, -0.000000f,  0.000000f, -1.148145f,
83
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
84
};
85
const float BT2020_10bit_full_rgb_to_yuv[] = {
86
      0.262700f,  0.678000f,  0.059300f,  0.000000f,  0.000000f,
87
     -0.139630f, -0.360370f,  0.500000f,  0.000000f,  0.500489f,
88
      0.500000f, -0.459786f, -0.040214f,  0.000000f,  0.500489f,
89
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
90
};
91
const float BT2020_10bit_full_yuv_to_rgb[] = {
92
      1.000000f, -0.000000f,  1.474600f,  0.000000f, -0.738021f,
93
      1.000000f, -0.164553f, -0.571353f,  0.000000f,  0.368313f,
94
      1.000000f,  1.881400f, -0.000000f,  0.000000f, -0.941620f,
95
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
96
};
97
const float BT2020_10bit_limited_rgb_to_yuv[] = {
98
      0.224951f,  0.580575f,  0.050779f,  0.000000f,  0.062561f,
99
     -0.122296f, -0.315632f,  0.437928f,  0.000000f,  0.500489f,
100
      0.437928f, -0.402706f, -0.035222f,  0.000000f,  0.500489f,
101
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
102
};
103
const float BT2020_10bit_limited_yuv_to_rgb[] = {
104
      1.167808f, -0.000000f,  1.683611f,  0.000000f, -0.915688f,
105
      1.167808f, -0.187877f, -0.652337f,  0.000000f,  0.347458f,
106
      1.167808f,  2.148072f, -0.000000f,  0.000000f, -1.148145f,
107
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
108
};
109
const float BT2020_12bit_full_rgb_to_yuv[] = {
110
      0.262700f,  0.678000f,  0.059300f,  0.000000f,  0.000000f,
111
     -0.139630f, -0.360370f,  0.500000f,  0.000000f,  0.500122f,
112
      0.500000f, -0.459786f, -0.040214f,  0.000000f,  0.500122f,
113
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
114
};
115
const float BT2020_12bit_full_yuv_to_rgb[] = {
116
      1.000000f, -0.000000f,  1.474600f,  0.000000f, -0.737480f,
117
      1.000000f, -0.164553f, -0.571353f,  0.000000f,  0.368043f,
118
      1.000000f,  1.881400f, -0.000000f,  0.000000f, -0.940930f,
119
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
120
};
121
const float BT2020_12bit_limited_rgb_to_yuv[] = {
122
      0.224787f,  0.580149f,  0.050742f,  0.000000f,  0.062515f,
123
     -0.122206f, -0.315401f,  0.437607f,  0.000000f,  0.500122f,
124
      0.437607f, -0.402411f, -0.035196f,  0.000000f,  0.500122f,
125
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
126
};
127
const float BT2020_12bit_limited_yuv_to_rgb[] = {
128
      1.168664f, -0.000000f,  1.684846f,  0.000000f, -0.915688f,
129
      1.168664f, -0.188015f, -0.652816f,  0.000000f,  0.347458f,
130
      1.168664f,  2.149647f, -0.000000f,  0.000000f, -1.148145f,
131
      0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
132
};
133
134
static_assert(kJPEG_Full_SkYUVColorSpace            == 0, "");
135
static_assert(kRec601_Limited_SkYUVColorSpace       == 1, "");
136
static_assert(kRec709_Full_SkYUVColorSpace          == 2, "");
137
static_assert(kRec709_Limited_SkYUVColorSpace       == 3, "");
138
static_assert(kBT2020_8bit_Full_SkYUVColorSpace     == 4, "");
139
static_assert(kBT2020_8bit_Limited_SkYUVColorSpace  == 5, "");
140
static_assert(kBT2020_10bit_Full_SkYUVColorSpace    == 6, "");
141
static_assert(kBT2020_10bit_Limited_SkYUVColorSpace == 7, "");
142
static_assert(kBT2020_12bit_Full_SkYUVColorSpace    == 8, "");
143
static_assert(kBT2020_12bit_Limited_SkYUVColorSpace == 9, "");
144
145
const float* yuv_to_rgb_array[] = {
146
    JPEG_full_yuv_to_rgb,
147
    Rec601_limited_yuv_to_rgb,
148
    Rec709_full_yuv_to_rgb,
149
    Rec709_limited_yuv_to_rgb,
150
    BT2020_8bit_full_yuv_to_rgb,
151
    BT2020_8bit_limited_yuv_to_rgb,
152
    BT2020_10bit_full_yuv_to_rgb,
153
    BT2020_10bit_limited_yuv_to_rgb,
154
    BT2020_12bit_full_yuv_to_rgb,
155
    BT2020_12bit_limited_yuv_to_rgb,
156
};
157
158
const float* rgb_to_yuv_array[] = {
159
    JPEG_full_rgb_to_yuv,
160
    Rec601_limited_rgb_to_yuv,
161
    Rec709_full_rgb_to_yuv,
162
    Rec709_limited_rgb_to_yuv,
163
    BT2020_8bit_full_rgb_to_yuv,
164
    BT2020_8bit_limited_rgb_to_yuv,
165
    BT2020_10bit_full_rgb_to_yuv,
166
    BT2020_10bit_limited_rgb_to_yuv,
167
    BT2020_12bit_full_rgb_to_yuv,
168
    BT2020_12bit_limited_rgb_to_yuv,
169
};
170
171
constexpr size_t kSizeOfColorMatrix = 20 * sizeof(float);
172
173
0
void SkColorMatrix_RGB2YUV(SkYUVColorSpace cs, float m[20]) {
174
0
    if ((unsigned)cs < (unsigned)kIdentity_SkYUVColorSpace) {
175
0
        memcpy(m, rgb_to_yuv_array[(unsigned)cs], kSizeOfColorMatrix);
176
0
    } else {
177
0
        memset(m, 0, kSizeOfColorMatrix);
178
0
        m[0] = m[6] = m[12] = m[18] = 1;
179
0
    }
180
0
}
181
182
0
void SkColorMatrix_YUV2RGB(SkYUVColorSpace cs, float m[20]) {
183
0
    if ((unsigned)cs < (unsigned)kIdentity_SkYUVColorSpace) {
184
0
        memcpy(m, yuv_to_rgb_array[(unsigned)cs], kSizeOfColorMatrix);
185
0
    } else {
186
0
        memset(m, 0, kSizeOfColorMatrix);
187
0
        m[0] = m[6] = m[12] = m[18] = 1;
188
0
    }
189
0
}
190
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192
193
// we just drop the alpha rol/col from the colormatrix
194
// output is |        tr |
195
//           |  3x3   tg |
196
//           |        tb |
197
//           | 0 0 0  1  |
198
0
static void colormatrix_to_matrix44(const float src[20], SkM44* dst) {
199
0
    *dst = SkM44(src[ 0], src[ 1], src[ 2], src[ 4],
200
0
                 src[ 5], src[ 6], src[ 7], src[ 9],
201
0
                 src[10], src[11], src[12], src[14],
202
0
                       0,       0,       0,       1);
203
0
}
204
205
// input: ignore the bottom row
206
// output: inject identity row/column for alpha
207
0
static void matrix44_to_colormatrix(const SkM44& src, float dst[20]) {
208
0
    dst[0] = src.rc(0,0);
209
0
    dst[1] = src.rc(0,1);
210
0
    dst[2] = src.rc(0,2);
211
0
    dst[3] = 0;
212
0
    dst[4] = src.rc(0,3);    // tx
213
214
0
    dst[5] = src.rc(1,0);
215
0
    dst[6] = src.rc(1,1);
216
0
    dst[7] = src.rc(1,2);
217
0
    dst[8] = 0;
218
0
    dst[9] = src.rc(1,3);    // ty
219
220
0
    dst[10] = src.rc(2,0);
221
0
    dst[11] = src.rc(2,1);
222
0
    dst[12] = src.rc(2,2);
223
0
    dst[13] = 0;
224
0
    dst[14] = src.rc(2,3);   // tz
225
226
0
    dst[15] = dst[16] = dst[17] = dst[19] = 0;
227
0
    dst[18] = 1;
228
0
}
229
230
0
static void scale3(float m[], float s) {
231
0
    for (int i = 0; i < 3; ++i) {
232
0
        m[i] *= s;
233
0
    }
234
0
}
235
236
namespace {
237
enum Range { kFull, kLimited };
238
struct YUVCoeff {
239
    float   Kr, Kb;
240
    int     bits;
241
    Range   range;
242
};
243
244
const YUVCoeff gCoeff[] = {
245
    { 0.2990f, 0.1140f,  8, kFull    }, // kJPEG_Full_SkYUVColorSpace
246
    { 0.2990f, 0.1140f,  8, kLimited }, // kRec601_Limited_SkYUVColorSpace
247
    { 0.2126f, 0.0722f,  8, kFull    }, // kRec709_Full_SkYUVColorSpace
248
    { 0.2126f, 0.0722f,  8, kLimited }, // kRec709_Limited_SkYUVColorSpace
249
    { 0.2627f, 0.0593f,  8, kFull    }, // kBT2020_8bit_Full_SkYUVColorSpace
250
    { 0.2627f, 0.0593f,  8, kLimited }, // kBT2020_8bit_Limited_SkYUVColorSpace
251
    { 0.2627f, 0.0593f, 10, kFull    }, // kBT2020_10bit_Full_SkYUVColorSpace
252
    { 0.2627f, 0.0593f, 10, kLimited }, // kBT2020_10bit_Limited_SkYUVColorSpace
253
    { 0.2627f, 0.0593f, 12, kFull    }, // kBT2020_12bit_Full_SkYUVColorSpace
254
    { 0.2627f, 0.0593f, 12, kLimited }, // kBT2020_12bit_Limited_SkYUVColorSpace
255
};
256
}  // namespace
257
258
0
static void make_rgb_to_yuv_matrix(float mx[20], const YUVCoeff& c) {
259
0
    SkASSERT(c.bits >= 8);
260
0
    const float Kr = c.Kr;
261
0
    const float Kb = c.Kb;
262
0
    const float Kg = 1.0f - Kr - Kb;
263
0
    const float Cr = 0.5f / (1.0f - Kb);
264
0
    const float Cb = 0.5f / (1.0f - Kr);
265
266
0
    const int shift = c.bits - 8;
267
268
0
    const float denom = static_cast<float>((1 << c.bits) - 1);
269
0
    float scaleY  = 1.0f,
270
0
          addY    = 0.0f,
271
0
          scaleUV = 1.0f,
272
0
          addUV   = (128 << shift) / denom;
273
274
0
    if (c.range == kLimited) {
275
0
        scaleY  = (219 << shift) / denom;
276
0
        addY    = ( 16 << shift) / denom;
277
0
        scaleUV = (224 << shift) / denom;
278
0
    }
279
280
0
    float m[20] = {
281
0
          Kr,  Kg,   Kb,  0,  addY,
282
0
         -Kr, -Kg, 1-Kb,  0, addUV,
283
0
        1-Kr, -Kg,  -Kb,  0, addUV,
284
0
           0,   0,    0,  1,     0,
285
0
    };
286
0
    memcpy(mx, m, sizeof(m));
287
0
    scale3(mx +  0,      scaleY );
288
0
    scale3(mx +  5, Cr * scaleUV);
289
0
    scale3(mx + 10, Cb * scaleUV);
290
0
}
Unexecuted instantiation: SkYUVMath.cpp:make_rgb_to_yuv_matrix(float*, (anonymous namespace)::YUVCoeff const&)
Unexecuted instantiation: SkYUVMath.cpp:make_rgb_to_yuv_matrix(float*, (anonymous namespace)::YUVCoeff const&)
291
292
0
static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv) {
293
0
    const char* names[] = {
294
0
        "JPEG_full",
295
0
        "Rec601_limited",
296
0
        "Rec709_full",
297
0
        "Rec709_limited",
298
0
        "BT2020_8bit_full",
299
0
        "BT2020_8bit_limited",
300
0
        "BT2020_10bit_full",
301
0
        "BT2020_10bit_limited",
302
0
        "BT2020_12bit_full",
303
0
        "BT2020_12bit_limited",
304
0
    };
305
0
    const char* dirnames[] = {
306
0
        "yuv_to_rgb", "rgb_to_yuv",
307
0
    };
308
0
    SkDebugf("const float %s_%s[] = {\n", names[cs], dirnames[rgb2yuv]);
309
0
    for (int i = 0; i < 4; ++i) {
310
0
        SkDebugf("    ");
311
0
        for (int j = 0; j < 5; ++j) {
312
0
            SkDebugf(" %9.6ff,", m[i * 5 + j]);
313
0
        }
314
0
        SkDebugf("\n");
315
0
    }
316
0
    SkDebugf("};\n");
317
0
}
318
319
// Used to create the prebuilt tables for each colorspace.
320
// Don't remove this function, in case we want to recompute those tables in the future.
321
0
void SkColorMatrix_DumpYUVMatrixTables() {
322
0
    for (int i = 0; i < kLastEnum_SkYUVColorSpace; ++i) {
323
0
        SkYUVColorSpace cs = static_cast<SkYUVColorSpace>(i);
324
0
        float m[20];
325
0
        make_rgb_to_yuv_matrix(m, gCoeff[(unsigned)cs]);
326
0
        dump(m, cs, true);
327
0
        SkM44 m44, im44;
328
0
        colormatrix_to_matrix44(m, &m44);
329
0
        float im[20];
330
#ifdef SK_DEBUG
331
        // be sure our coversion between matrix44 and colormatrix is perfect
332
        matrix44_to_colormatrix(m44, im);
333
0
        SkASSERT(memcmp(m, im, sizeof(im)) == 0);
334
#endif
335
0
        SkAssertResult(m44.invert(&im44));
336
0
        matrix44_to_colormatrix(im44, im);
337
0
        dump(im, cs, false);
338
0
    }
339
0
}
Unexecuted instantiation: SkColorMatrix_DumpYUVMatrixTables()
Unexecuted instantiation: SkColorMatrix_DumpYUVMatrixTables()