| 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 cb = 0.5f / (1.0f - kb); | 
| 26 |   const float cr = 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 = cb; | 
| 34 |   float scale_v = cr; | 
| 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 | // Derived using the following formulas: | 
| 64 | // Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16 | 
| 65 | // U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128 | 
| 66 | // V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128 | 
| 67 | static const SharpYuvConversionMatrix kWebpMatrix = { | 
| 68 |   {16839, 33059, 6420, 16 << 16}, | 
| 69 |   {-9719, -19081, 28800, 128 << 16}, | 
| 70 |   {28800, -24116, -4684, 128 << 16}, | 
| 71 | }; | 
| 72 | // Kr=0.2990f Kb=0.1140f bit_depth=8 range=kSharpYuvRangeLimited | 
| 73 | static const SharpYuvConversionMatrix kRec601LimitedMatrix = { | 
| 74 |   {16829, 33039, 6416, 16 << 16}, | 
| 75 |   {-9714, -19071, 28784, 128 << 16}, | 
| 76 |   {28784, -24103, -4681, 128 << 16}, | 
| 77 | }; | 
| 78 | // Kr=0.2990f Kb=0.1140f bit_depth=8 range=kSharpYuvRangeFull | 
| 79 | static const SharpYuvConversionMatrix kRec601FullMatrix = { | 
| 80 |   {19595, 38470, 7471, 0}, | 
| 81 |   {-11058, -21710, 32768, 128 << 16}, | 
| 82 |   {32768, -27439, -5329, 128 << 16}, | 
| 83 | }; | 
| 84 | // Kr=0.2126f Kb=0.0722f bit_depth=8 range=kSharpYuvRangeLimited | 
| 85 | static const SharpYuvConversionMatrix kRec709LimitedMatrix = { | 
| 86 |   {11966, 40254, 4064, 16 << 16}, | 
| 87 |   {-6596, -22189, 28784, 128 << 16}, | 
| 88 |   {28784, -26145, -2639, 128 << 16}, | 
| 89 | }; | 
| 90 | // Kr=0.2126f Kb=0.0722f bit_depth=8 range=kSharpYuvRangeFull | 
| 91 | static const SharpYuvConversionMatrix kRec709FullMatrix = { | 
| 92 |   {13933, 46871, 4732, 0}, | 
| 93 |   {-7509, -25259, 32768, 128 << 16}, | 
| 94 |   {32768, -29763, -3005, 128 << 16}, | 
| 95 | }; | 
| 96 |  | 
| 97 | const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix( | 
| 98 |     SharpYuvMatrixType matrix_type) { | 
| 99 |   switch (matrix_type) { | 
| 100 |     case kSharpYuvMatrixWebp: | 
| 101 |       return &kWebpMatrix; | 
| 102 |     case kSharpYuvMatrixRec601Limited: | 
| 103 |       return &kRec601LimitedMatrix; | 
| 104 |     case kSharpYuvMatrixRec601Full: | 
| 105 |       return &kRec601FullMatrix; | 
| 106 |     case kSharpYuvMatrixRec709Limited: | 
| 107 |       return &kRec709LimitedMatrix; | 
| 108 |     case kSharpYuvMatrixRec709Full: | 
| 109 |       return &kRec709FullMatrix; | 
| 110 |     case kSharpYuvMatrixNum: | 
| 111 |       return NULL; | 
| 112 |   } | 
| 113 |   return NULL; | 
| 114 | } | 
| 115 |  |