[vlc-devel] [PATCH 3/7] opengl: generate chroma conversion matrices

Alexandre Janniaux ajanni at videolabs.io
Thu Jan 23 11:50:20 CET 2020


Hi,

Comments inline,

On Wed, Jan 22, 2020 at 01:33:45PM +0100, Romain Vimont wrote:
> Construct chroma conversion matrices programmatically, from the luma
> weight of the R, G and B components.
>
> This allows to combine (multiply) matrices and paves the way to properly
> support full color range (for now, the range is hardcoded to
> COLOR_RANGE_LIMITED to match the previous implementation).
> ---
>  .../video_output/opengl/fragment_shaders.c    | 120 +++++++++++++-----
>  1 file changed, 88 insertions(+), 32 deletions(-)
>
> diff --git a/modules/video_output/opengl/fragment_shaders.c b/modules/video_output/opengl/fragment_shaders.c
> index 46b65aa69b..7fbbca81c7 100644
> --- a/modules/video_output/opengl/fragment_shaders.c
> +++ b/modules/video_output/opengl/fragment_shaders.c
> @@ -37,6 +37,90 @@
>  #include "internal.h"
>  #include "vout_helper.h"
>
> +static const float MATRIX_COLOR_RANGE_LIMITED[4*3] = {
> +    255.f/219,         0,         0, -255.f/219 *  16.f/255,
> +            0, 255.f/224,         0, -255.f/224 * 128.f/255,
> +            0,         0, 255.f/224, -255.f/224 * 128.f/255,
> +};
> +
> +static const float MATRIX_COLOR_RANGE_FULL[4*3] = {
> +    1, 0, 0,          0,
> +    0, 1, 0, -128.f/255,
> +    0, 0, 1, -128.f/255,
> +};
> +
> +/*
> + * Construct the transformation matrix from the luma weight of the red and blue
> + * component (the green component is deduced).
> + */
> +#define MATRIX_YUV_TO_RGB(KR, KB) \
> +    MATRIX_YUV_TO_RGB_(KR, (1-(KR)-(KB)), KB)
> +
> +/*
> + * Construct the transformation matrix from the luma weight of the RGB
> + * components.
> + *
> + * KR: luma weight of the red component
> + * KG: luma weight of the green component
> + * KB: luma weight of the blue component
> + *
> + * By definition, KR + KG + KB == 1.
> + *
> + * Ref: <https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion>
> + * Ref: libplacebo: src/colorspace.c:luma_coeffs()
> + * */
> +#define MATRIX_YUV_TO_RGB_(KR, KG, KB) { \
> +    1,                         0,              2*(1.f-(KR)), \
> +    1, -2*(1.f-(KB))*((KB)/(KG)), -2*(1.f-(KR))*((KR)/(KG)), \
> +    1,              2*(1.f-(KB)),                         0, \
> +}
> +
> +static const float MATRIX_BT601[3*3] = MATRIX_YUV_TO_RGB(0.299f, 0.114f);
> +static const float MATRIX_BT709[3*3] = MATRIX_YUV_TO_RGB(0.2126f, 0.0722f);
> +static const float MATRIX_BT2020[3*3] = MATRIX_YUV_TO_RGB(0.2627f, 0.0593f);
> +
> +static void
> +init_conv_matrix(float conv_matrix_out[],
> +                 video_color_space_t color_space,
> +                 video_color_range_t color_range)
> +{
> +    const float *space_matrix;
> +    switch (color_space) {
> +        case COLOR_SPACE_BT601:
> +            space_matrix = MATRIX_BT601;
> +            break;
> +        case COLOR_SPACE_BT2020:
> +            space_matrix = MATRIX_BT2020;
> +            break;
> +        default:
> +            space_matrix = MATRIX_BT709;

It might be worthy to handle the BT709 case and have a default
setting MATRIX_BT709 while raising a warning, to help debugging
next time color are not correct.

> +    }
> +
> +    /* Init the conversion matrix in row-major order. */
> +
> +    const float *range_matrix = color_range == COLOR_RANGE_FULL
> +                              ? MATRIX_COLOR_RANGE_FULL
> +                              : MATRIX_COLOR_RANGE_LIMITED;
> +    /* Multiply the matrices on CPU once for all */
> +    for (int x = 0; x < 4; ++x)
> +    {
> +        for (int y = 0; y < 3; ++y)
> +        {
> +            float sum = 0;
> +            for (int k = 0; k < 3; ++k)
> +                sum += space_matrix[y * 3 + k] * range_matrix[k * 4 + x];
> +            conv_matrix_out[y * 4 + x] = sum;
> +        }
> +    }

The question raised by other here was:

Is it worthy to do this computation in double precision ?

> +
> +    /* Add a row to fill a 4x4 matrix.
> +     * (non-square matrices are not supported on old OpenGL ES versions) */
> +    conv_matrix_out[12] = 0;
> +    conv_matrix_out[13] = 0;
> +    conv_matrix_out[14] = 0;
> +    conv_matrix_out[15] = 1;
> +}
> +
>  static int
>  tc_yuv_base_init(opengl_tex_converter_t *tc, vlc_fourcc_t chroma,
>                   const vlc_chroma_description_t *desc,
> @@ -52,38 +136,10 @@ tc_yuv_base_init(opengl_tex_converter_t *tc, vlc_fourcc_t chroma,
>                                   / ((1 << desc->pixel_bits) - 1);
>      }
>
> -    /* [R/G/B][Y U V O] from TV range to full range
> -     * XXX we could also do hue/brightness/constrast/gamma
> -     * by simply changing the coefficients
> -     */
> -    static const float matrix_bt601_tv2full[12] = {
> -        1.164383561643836,  0.0000,             1.596026785714286, -0.874202217873451 ,
> -        1.164383561643836, -0.391762290094914, -0.812967647237771,  0.531667823499146 ,
> -        1.164383561643836,  2.017232142857142,  0.0000,            -1.085630789302022 ,
> -    };
> -    static const float matrix_bt709_tv2full[12] = {
> -        1.164383561643836,  0.0000,             1.792741071428571, -0.972945075016308 ,
> -        1.164383561643836, -0.21324861427373,  -0.532909328559444,  0.301482665475862 ,
> -        1.164383561643836,  2.112401785714286,  0.0000,            -1.133402217873451 ,
> -    };
> -    static const float matrix_bt2020_tv2full[12] = {
> -        1.164383530616760,  0.0000,             1.678674221038818, -0.915687978267670 ,
> -        1.164383530616760, -0.187326118350029, -0.650424420833588,  0.347458571195602 ,
> -        1.164383530616760,  2.141772270202637,  0.0000,            -1.148145079612732 ,
> -    };
> -
> -    const float *matrix;
> -    switch (yuv_space)
> -    {
> -        case COLOR_SPACE_BT601:
> -            matrix = matrix_bt601_tv2full;
> -            break;
> -        case COLOR_SPACE_BT2020:
> -            matrix = matrix_bt2020_tv2full;
> -            break;
> -        default:
> -            matrix = matrix_bt709_tv2full;
> -    };
> +    /* The current implementation always converts from limited to full range. */
> +    const video_color_range_t range = COLOR_RANGE_LIMITED;
> +    float matrix[4*4];
> +    init_conv_matrix(matrix, yuv_space, range);
>
>      for (int i = 0; i < 4; i++) {
>          float correction = i < 3 ? yuv_range_correction : 1.f;
> --
> 2.25.0
>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list