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