| 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(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(kr * scale_y); |
| 46 | matrix->rgb_to_y[1] = ToFixed16(kg * scale_y); |
| 47 | matrix->rgb_to_y[2] = ToFixed16(kb * scale_y); |
| 48 | matrix->rgb_to_y[3] = ToFixed16(add_y); |
| 49 | |
| 50 | matrix->rgb_to_u[0] = ToFixed16(-kr * scale_u); |
| 51 | matrix->rgb_to_u[1] = ToFixed16(-kg * scale_u); |
| 52 | matrix->rgb_to_u[2] = ToFixed16((1 - kb) * scale_u); |
| 53 | matrix->rgb_to_u[3] = ToFixed16(add_uv); |
| 54 | |
| 55 | matrix->rgb_to_v[0] = ToFixed16((1 - kr) * scale_v); |
| 56 | matrix->rgb_to_v[1] = ToFixed16(-kg * scale_v); |
| 57 | matrix->rgb_to_v[2] = ToFixed16(-kb * scale_v); |
| 58 | matrix->rgb_to_v[3] = ToFixed16(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 | |