1 | // Copyright 2022 Google Inc. All Rights Reserved. |
2 | // |
3 | // Use of this source code is governed by a BSD-style license |
4 | // that can be found in the COPYING file in the root of the source |
5 | // tree. An additional intellectual property rights grant can be found |
6 | // in the file PATENTS. All contributing project authors may |
7 | // be found in the AUTHORS file in the root of the source tree. |
8 | // ----------------------------------------------------------------------------- |
9 | // |
10 | // Colorspace utilities. |
11 | |
12 | #include "sharpyuv/sharpyuv_csp.h" |
13 | |
14 | #include <assert.h> |
15 | #include <math.h> |
16 | #include <stddef.h> |
17 | |
18 | static int ToFixed16(float f) { return (int)floor(x: f * (1 << 16) + 0.5f); } |
19 | |
20 | void SharpYuvComputeConversionMatrix(const SharpYuvColorSpace* yuv_color_space, |
21 | SharpYuvConversionMatrix* matrix) { |
22 | const float kr = yuv_color_space->kr; |
23 | const float kb = yuv_color_space->kb; |
24 | const float kg = 1.0f - kr - kb; |
25 | const float cr = 0.5f / (1.0f - kb); |
26 | const float cb = 0.5f / (1.0f - kr); |
27 | |
28 | const int shift = yuv_color_space->bit_depth - 8; |
29 | |
30 | const float denom = (float)((1 << yuv_color_space->bit_depth) - 1); |
31 | float scale_y = 1.0f; |
32 | float add_y = 0.0f; |
33 | float scale_u = cr; |
34 | float scale_v = cb; |
35 | float add_uv = (float)(128 << shift); |
36 | assert(yuv_color_space->bit_depth >= 8); |
37 | |
38 | if (yuv_color_space->range == kSharpYuvRangeLimited) { |
39 | scale_y *= (219 << shift) / denom; |
40 | scale_u *= (224 << shift) / denom; |
41 | scale_v *= (224 << shift) / denom; |
42 | add_y = (float)(16 << shift); |
43 | } |
44 | |
45 | matrix->rgb_to_y[0] = ToFixed16(f: kr * scale_y); |
46 | matrix->rgb_to_y[1] = ToFixed16(f: kg * scale_y); |
47 | matrix->rgb_to_y[2] = ToFixed16(f: kb * scale_y); |
48 | matrix->rgb_to_y[3] = ToFixed16(f: add_y); |
49 | |
50 | matrix->rgb_to_u[0] = ToFixed16(f: -kr * scale_u); |
51 | matrix->rgb_to_u[1] = ToFixed16(f: -kg * scale_u); |
52 | matrix->rgb_to_u[2] = ToFixed16(f: (1 - kb) * scale_u); |
53 | matrix->rgb_to_u[3] = ToFixed16(f: add_uv); |
54 | |
55 | matrix->rgb_to_v[0] = ToFixed16(f: (1 - kr) * scale_v); |
56 | matrix->rgb_to_v[1] = ToFixed16(f: -kg * scale_v); |
57 | matrix->rgb_to_v[2] = ToFixed16(f: -kb * scale_v); |
58 | matrix->rgb_to_v[3] = ToFixed16(f: add_uv); |
59 | } |
60 | |
61 | // Matrices are in YUV_FIX fixed point precision. |
62 | // WebP's matrix, similar but not identical to kRec601LimitedMatrix. |
63 | static const SharpYuvConversionMatrix kWebpMatrix = { |
64 | {16839, 33059, 6420, 16 << 16}, |
65 | {-9719, -19081, 28800, 128 << 16}, |
66 | {28800, -24116, -4684, 128 << 16}, |
67 | }; |
68 | // Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeLimited |
69 | static const SharpYuvConversionMatrix kRec601LimitedMatrix = { |
70 | {16829, 33039, 6416, 16 << 16}, |
71 | {-9714, -19071, 28784, 128 << 16}, |
72 | {28784, -24103, -4681, 128 << 16}, |
73 | }; |
74 | // Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeFull |
75 | static const SharpYuvConversionMatrix kRec601FullMatrix = { |
76 | {19595, 38470, 7471, 0}, |
77 | {-11058, -21710, 32768, 128 << 16}, |
78 | {32768, -27439, -5329, 128 << 16}, |
79 | }; |
80 | // Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeLimited |
81 | static const SharpYuvConversionMatrix kRec709LimitedMatrix = { |
82 | {11966, 40254, 4064, 16 << 16}, |
83 | {-6596, -22189, 28784, 128 << 16}, |
84 | {28784, -26145, -2639, 128 << 16}, |
85 | }; |
86 | // Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeFull |
87 | static const SharpYuvConversionMatrix kRec709FullMatrix = { |
88 | {13933, 46871, 4732, 0}, |
89 | {-7509, -25259, 32768, 128 << 16}, |
90 | {32768, -29763, -3005, 128 << 16}, |
91 | }; |
92 | |
93 | const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix( |
94 | SharpYuvMatrixType matrix_type) { |
95 | switch (matrix_type) { |
96 | case kSharpYuvMatrixWebp: |
97 | return &kWebpMatrix; |
98 | case kSharpYuvMatrixRec601Limited: |
99 | return &kRec601LimitedMatrix; |
100 | case kSharpYuvMatrixRec601Full: |
101 | return &kRec601FullMatrix; |
102 | case kSharpYuvMatrixRec709Limited: |
103 | return &kRec709LimitedMatrix; |
104 | case kSharpYuvMatrixRec709Full: |
105 | return &kRec709FullMatrix; |
106 | case kSharpYuvMatrixNum: |
107 | return NULL; |
108 | } |
109 | return NULL; |
110 | } |
111 | |