Home | History | Annotate | Download | only in vl
      1 /**************************************************************************
      2  *
      3  * Copyright 2009 Younes Manton.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 #include "util/u_math.h"
     29 #include "util/u_debug.h"
     30 
     31 #include "vl_csc.h"
     32 
     33 /*
     34  * Color space conversion formulas
     35  *
     36  * To convert YCbCr to RGB,
     37  *    vec4  ycbcr, rgb
     38  *    mat44 csc
     39  *    rgb = csc * ycbcr
     40  *
     41  * To calculate the color space conversion matrix csc with ProcAmp adjustments,
     42  *    mat44 csc, cstd, procamp, bias
     43  *    csc = cstd * (procamp * bias)
     44  *
     45  * Where cstd is a matrix corresponding to one of the color standards (BT.601, BT.709, etc)
     46  * adjusted for the kind of YCbCr -> RGB mapping wanted (1:1, full),
     47  * bias is a matrix corresponding to the kind of YCbCr -> RGB mapping wanted (1:1, full)
     48  *
     49  * To calculate procamp,
     50  *    mat44 procamp, hue, saturation, brightness, contrast
     51  *    procamp = brightness * (saturation * (contrast * hue))
     52  * Alternatively,
     53  *    procamp = saturation * (brightness * (contrast * hue))
     54  *
     55  * contrast
     56  * [ c, 0, 0, 0]
     57  * [ 0, c, 0, 0]
     58  * [ 0, 0, c, 0]
     59  * [ 0, 0, 0, 1]
     60  *
     61  * brightness
     62  * [ 1, 0, 0, b]
     63  * [ 0, 1, 0, 0]
     64  * [ 0, 0, 1, 0]
     65  * [ 0, 0, 0, 1]
     66  *
     67  * saturation
     68  * [ 1, 0, 0, 0]
     69  * [ 0, s, 0, 0]
     70  * [ 0, 0, s, 0]
     71  * [ 0, 0, 0, 1]
     72  *
     73  * hue
     74  * [ 1,       0,      0, 0]
     75  * [ 0,  cos(h), sin(h), 0]
     76  * [ 0, -sin(h), cos(h), 0]
     77  * [ 0,       0,      0, 1]
     78  *
     79  * procamp
     80  * [ c,           0,          0, b]
     81  * [ 0,  c*s*cos(h), c*s*sin(h), 0]
     82  * [ 0, -c*s*sin(h), c*s*cos(h), 0]
     83  * [ 0,           0,          0, 1]
     84  *
     85  * bias
     86  * [ 1, 0, 0,  ybias]
     87  * [ 0, 1, 0, cbbias]
     88  * [ 0, 0, 1, crbias]
     89  * [ 0, 0, 0,      1]
     90  *
     91  * csc
     92  * [ c*cstd[ 0], c*cstd[ 1]*s*cos(h) - c*cstd[ 2]*s*sin(h), c*cstd[ 2]*s*cos(h) + c*cstd[ 1]*s*sin(h), cstd[ 3] + cstd[ 0]*(b + c*ybias) + cstd[ 1]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[ 2]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
     93  * [ c*cstd[ 4], c*cstd[ 5]*s*cos(h) - c*cstd[ 6]*s*sin(h), c*cstd[ 6]*s*cos(h) + c*cstd[ 5]*s*sin(h), cstd[ 7] + cstd[ 4]*(b + c*ybias) + cstd[ 5]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[ 6]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
     94  * [ c*cstd[ 8], c*cstd[ 9]*s*cos(h) - c*cstd[10]*s*sin(h), c*cstd[10]*s*cos(h) + c*cstd[ 9]*s*sin(h), cstd[11] + cstd[ 8]*(b + c*ybias) + cstd[ 9]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[10]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
     95  * [ c*cstd[12], c*cstd[13]*s*cos(h) - c*cstd[14]*s*sin(h), c*cstd[14]*s*cos(h) + c*cstd[13]*s*sin(h), cstd[15] + cstd[12]*(b + c*ybias) + cstd[13]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[14]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
     96  */
     97 
     98 /*
     99  * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
    100  * Y is in [16,235], Cb and Cr are in [16,240]
    101  * R, G, and B are in [16,235]
    102  */
    103 static const vl_csc_matrix bt_601 =
    104 {
    105    { 1.0f,  0.0f,    1.371f, 0.0f, },
    106    { 1.0f, -0.336f, -0.698f, 0.0f, },
    107    { 1.0f,  1.732f,  0.0f,   0.0f, }
    108 };
    109 
    110 /*
    111  * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
    112  * Y is in [16,235], Cb and Cr are in [16,240]
    113  * R, G, and B are in [0,255]
    114  */
    115 static const vl_csc_matrix bt_601_full =
    116 {
    117    { 1.164f,  0.0f,    1.596f, 0.0f, },
    118    { 1.164f, -0.391f, -0.813f, 0.0f, },
    119    { 1.164f,  2.018f,  0.0f,   0.0f, }
    120 };
    121 
    122 /*
    123  * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
    124  * Y is in [16,235], Cb and Cr are in [16,240]
    125  * R, G, and B are in [16,235]
    126  */
    127 static const vl_csc_matrix bt_709 =
    128 {
    129    { 1.0f,  0.0f,    1.540f, 0.0f, },
    130    { 1.0f, -0.183f, -0.459f, 0.0f, },
    131    { 1.0f,  1.816f,  0.0f,   0.0f, }
    132 };
    133 
    134 /*
    135  * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
    136  * Y is in [16,235], Cb and Cr are in [16,240]
    137  * R, G, and B are in [0,255]
    138  */
    139 static const vl_csc_matrix bt_709_full =
    140 {
    141    { 1.164f,  0.0f,    1.793f, 0.0f, },
    142    { 1.164f, -0.213f, -0.534f, 0.0f, },
    143    { 1.164f,  2.115f,  0.0f,   0.0f, }
    144 };
    145 
    146 static const vl_csc_matrix smpte240m =
    147 {
    148    { 1.0f,  0.0f,    1.582f, 0.0f, },
    149    { 1.0f, -0.228f, -0.478f, 0.0f, },
    150    { 1.0f,  1.833f,  0.0f,   0.0f, }
    151 };
    152 
    153 static const vl_csc_matrix smpte240m_full =
    154 {
    155    { 1.164f,  0.0f,    1.794f, 0.0f, },
    156    { 1.164f, -0.258f, -0.543f, 0.0f, },
    157    { 1.164f,  2.079f,  0.0f,   0.0f, }
    158 };
    159 
    160 static const vl_csc_matrix identity =
    161 {
    162    { 1.0f, 0.0f, 0.0f, 0.0f, },
    163    { 0.0f, 1.0f, 0.0f, 0.0f, },
    164    { 0.0f, 0.0f, 1.0f, 0.0f, }
    165 };
    166 
    167 const struct vl_procamp vl_default_procamp = {
    168    0.0f,  /* brightness */
    169    1.0f,  /* contrast   */
    170    1.0f,  /* saturation */
    171    0.0f   /* hue        */
    172 };
    173 
    174 void vl_csc_get_matrix(enum VL_CSC_COLOR_STANDARD cs,
    175                        struct vl_procamp *procamp,
    176                        bool full_range,
    177                        vl_csc_matrix *matrix)
    178 {
    179    float ybias = full_range ? -16.0f/255.0f : 0.0f;
    180    float cbbias = -128.0f/255.0f;
    181    float crbias = -128.0f/255.0f;
    182 
    183    const struct vl_procamp *p = procamp ? procamp : &vl_default_procamp;
    184    float c = p->contrast;
    185    float s = p->saturation;
    186    float b = p->brightness;
    187    float h = p->hue;
    188 
    189    const vl_csc_matrix *cstd;
    190 
    191    assert(matrix);
    192 
    193    switch (cs) {
    194       case VL_CSC_COLOR_STANDARD_BT_601:
    195          cstd = full_range ? &bt_601_full : &bt_601;
    196          break;
    197       case VL_CSC_COLOR_STANDARD_BT_709:
    198          cstd = full_range ? &bt_709_full : &bt_709;
    199          break;
    200       case VL_CSC_COLOR_STANDARD_SMPTE_240M:
    201          cstd = full_range ? &smpte240m_full : &smpte240m;
    202          break;
    203       case VL_CSC_COLOR_STANDARD_IDENTITY:
    204       default:
    205          assert(cs == VL_CSC_COLOR_STANDARD_IDENTITY);
    206          memcpy(matrix, identity, sizeof(vl_csc_matrix));
    207          return;
    208    }
    209 
    210    (*matrix)[0][0] = c * (*cstd)[0][0];
    211    (*matrix)[0][1] = c * (*cstd)[0][1] * s * cosf(h) - c * (*cstd)[0][2] * s * sinf(h);
    212    (*matrix)[0][2] = c * (*cstd)[0][2] * s * cosf(h) + c * (*cstd)[0][1] * s * sinf(h);
    213    (*matrix)[0][3] = (*cstd)[0][3] + (*cstd)[0][0] * (b + c * ybias) +
    214                      (*cstd)[0][1] * (c * cbbias * s * cosf(h) + c * crbias * s * sinf(h)) +
    215                      (*cstd)[0][2] * (c * crbias * s * cosf(h) - c * cbbias * s * sinf(h));
    216 
    217    (*matrix)[1][0] = c * (*cstd)[1][0];
    218    (*matrix)[1][1] = c * (*cstd)[1][1] * s * cosf(h) - c * (*cstd)[1][2] * s * sinf(h);
    219    (*matrix)[1][2] = c * (*cstd)[1][2] * s * cosf(h) + c * (*cstd)[1][1] * s * sinf(h);
    220    (*matrix)[1][3] = (*cstd)[1][3] + (*cstd)[1][0] * (b + c * ybias) +
    221                      (*cstd)[1][1] * (c * cbbias * s * cosf(h) + c * crbias * s * sinf(h)) +
    222                      (*cstd)[1][2] * (c * crbias * s * cosf(h) - c * cbbias * s * sinf(h));
    223 
    224    (*matrix)[2][0] = c * (*cstd)[2][0];
    225    (*matrix)[2][1] = c * (*cstd)[2][1] * s * cosf(h) - c * (*cstd)[2][2] * s * sinf(h);
    226    (*matrix)[2][2] = c * (*cstd)[2][2] * s * cosf(h) + c * (*cstd)[2][1] * s * sinf(h);
    227    (*matrix)[2][3] = (*cstd)[2][3] + (*cstd)[2][0] * (b + c * ybias) +
    228                      (*cstd)[2][1] * (c * cbbias * s * cosf(h) + c * crbias * s * sinf(h)) +
    229                      (*cstd)[2][2] * (c * crbias * s * cosf(h) - c * cbbias * s * sinf(h));
    230 }
    231