test/testyuv_cvt.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 07 Dec 2017 16:08:09 -0800
changeset 11730 ac6c607e065c
parent 11702 cf166abbde4a
child 11811 5d94cb6b24d3
permissions -rw-r--r--
Enable building the Metal renderer by default, and weak link the Metal framework so the SDL library is safe to use on older Macs
Also generate iOS versions of the Metal shaders
slouken@11702
     1
/*
slouken@11702
     2
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
slouken@11702
     3
slouken@11702
     4
  This software is provided 'as-is', without any express or implied
slouken@11702
     5
  warranty.  In no event will the authors be held liable for any damages
slouken@11702
     6
  arising from the use of this software.
slouken@11702
     7
slouken@11702
     8
  Permission is granted to anyone to use this software for any purpose,
slouken@11702
     9
  including commercial applications, and to alter it and redistribute it
slouken@11702
    10
  freely.
slouken@11702
    11
*/
slouken@11702
    12
slouken@11702
    13
#include "SDL.h"
slouken@11702
    14
slouken@11702
    15
#include "testyuv_cvt.h"
slouken@11702
    16
slouken@11702
    17
slouken@11702
    18
static float clip3(float x, float y, float z)
slouken@11702
    19
{
slouken@11702
    20
    return ((z < x) ? x : ((z > y) ? y : z));
slouken@11702
    21
}
slouken@11702
    22
slouken@11702
    23
static void RGBtoYUV(Uint8 * rgb, int *yuv, SDL_YUV_CONVERSION_MODE mode, int monochrome, int luminance)
slouken@11702
    24
{
slouken@11702
    25
    if (mode == SDL_YUV_CONVERSION_JPEG) {
slouken@11702
    26
        /* Full range YUV */
slouken@11702
    27
        yuv[0] = (int)(0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]);
slouken@11702
    28
        yuv[1] = (int)((rgb[2] - yuv[0]) * 0.565 + 128);
slouken@11702
    29
        yuv[2] = (int)((rgb[0] - yuv[0]) * 0.713 + 128);
slouken@11702
    30
    } else {
slouken@11702
    31
        // This formula is from Microsoft's documentation:
slouken@11702
    32
        // https://msdn.microsoft.com/en-us/library/windows/desktop/dd206750(v=vs.85).aspx
slouken@11702
    33
        // L = Kr * R + Kb * B + (1 - Kr - Kb) * G
slouken@11702
    34
        // Y =                   floor(2^(M-8) * (219*(L-Z)/S + 16) + 0.5);
slouken@11702
    35
        // U = clip3(0, (2^M)-1, floor(2^(M-8) * (112*(B-L) / ((1-Kb)*S) + 128) + 0.5));
slouken@11702
    36
        // V = clip3(0, (2^M)-1, floor(2^(M-8) * (112*(R-L) / ((1-Kr)*S) + 128) + 0.5));
slouken@11702
    37
        float S, Z, R, G, B, L, Kr, Kb, Y, U, V;
slouken@11702
    38
slouken@11702
    39
        if (mode == SDL_YUV_CONVERSION_BT709) {
slouken@11702
    40
            /* BT.709 */
slouken@11702
    41
            Kr = 0.2126f;
slouken@11702
    42
            Kb = 0.0722f;
slouken@11702
    43
        } else {
slouken@11702
    44
            /* BT.601 */
slouken@11702
    45
            Kr = 0.299f;
slouken@11702
    46
            Kb = 0.114f;
slouken@11702
    47
        }
slouken@11702
    48
slouken@11702
    49
        S = 255.0f;
slouken@11702
    50
        Z = 0.0f;
slouken@11702
    51
        R = rgb[0];
slouken@11702
    52
        G = rgb[1];
slouken@11702
    53
        B = rgb[2];
slouken@11702
    54
        L = Kr * R + Kb * B + (1 - Kr - Kb) * G;
slouken@11702
    55
        Y = (Uint8)SDL_floorf((219*(L-Z)/S + 16) + 0.5f);
slouken@11702
    56
        U = (Uint8)clip3(0, 255, SDL_floorf((112.0f*(B-L) / ((1.0f-Kb)*S) + 128) + 0.5f));
slouken@11702
    57
        V = (Uint8)clip3(0, 255, SDL_floorf((112.0f*(R-L) / ((1.0f-Kr)*S) + 128) + 0.5f));
slouken@11702
    58
slouken@11702
    59
        yuv[0] = (Uint8)Y;
slouken@11702
    60
        yuv[1] = (Uint8)U;
slouken@11702
    61
        yuv[2] = (Uint8)V;
slouken@11702
    62
    }
slouken@11702
    63
slouken@11702
    64
    if (monochrome) {
slouken@11702
    65
        yuv[1] = 128;
slouken@11702
    66
        yuv[2] = 128;
slouken@11702
    67
    }
slouken@11702
    68
slouken@11702
    69
    if (luminance != 100) {
slouken@11702
    70
        yuv[0] = yuv[0] * luminance / 100;
slouken@11702
    71
        if (yuv[0] > 255)
slouken@11702
    72
            yuv[0] = 255;
slouken@11702
    73
    }
slouken@11702
    74
}
slouken@11702
    75
slouken@11702
    76
static void ConvertRGBtoPlanar2x2(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, SDL_YUV_CONVERSION_MODE mode, int monochrome, int luminance)
slouken@11702
    77
{
slouken@11702
    78
    int x, y;
slouken@11702
    79
    int yuv[4][3];
slouken@11702
    80
    Uint8 *Y1, *Y2, *U, *V;
slouken@11702
    81
    Uint8 *rgb1, *rgb2;
slouken@11702
    82
    int rgb_row_advance = (pitch - w*3) + pitch;
slouken@11702
    83
    int UV_advance;
slouken@11702
    84
slouken@11702
    85
    rgb1 = src;
slouken@11702
    86
    rgb2 = src + pitch;
slouken@11702
    87
slouken@11702
    88
    Y1 = out;
slouken@11702
    89
    Y2 = Y1 + w;
slouken@11702
    90
    switch (format) {
slouken@11702
    91
    case SDL_PIXELFORMAT_YV12:
slouken@11702
    92
        V = (Y1 + h * w);
slouken@11702
    93
        U = V + ((h + 1)/2)*((w + 1)/2);
slouken@11702
    94
        UV_advance = 1;
slouken@11702
    95
        break;
slouken@11702
    96
    case SDL_PIXELFORMAT_IYUV:
slouken@11702
    97
        U = (Y1 + h * w);
slouken@11702
    98
        V = U + ((h + 1)/2)*((w + 1)/2);
slouken@11702
    99
        UV_advance = 1;
slouken@11702
   100
        break;
slouken@11702
   101
    case SDL_PIXELFORMAT_NV12:
slouken@11702
   102
        U = (Y1 + h * w);
slouken@11702
   103
        V = U + 1;
slouken@11702
   104
        UV_advance = 2;
slouken@11702
   105
        break;
slouken@11702
   106
    case SDL_PIXELFORMAT_NV21:
slouken@11702
   107
        V = (Y1 + h * w);
slouken@11702
   108
        U = V + 1;
slouken@11702
   109
        UV_advance = 2;
slouken@11702
   110
        break;
slouken@11702
   111
    default:
slouken@11702
   112
        SDL_assert(!"Unsupported planar YUV format");
slouken@11702
   113
        return;
slouken@11702
   114
    }
slouken@11702
   115
slouken@11702
   116
    for (y = 0; y < (h - 1); y += 2) {
slouken@11702
   117
        for (x = 0; x < (w - 1); x += 2) {
slouken@11702
   118
            RGBtoYUV(rgb1, yuv[0], mode, monochrome, luminance);
slouken@11702
   119
            rgb1 += 3;
slouken@11702
   120
            *Y1++ = (Uint8)yuv[0][0];
slouken@11702
   121
slouken@11702
   122
            RGBtoYUV(rgb1, yuv[1], mode, monochrome, luminance);
slouken@11702
   123
            rgb1 += 3;
slouken@11702
   124
            *Y1++ = (Uint8)yuv[1][0];
slouken@11702
   125
slouken@11702
   126
            RGBtoYUV(rgb2, yuv[2], mode, monochrome, luminance);
slouken@11702
   127
            rgb2 += 3;
slouken@11702
   128
            *Y2++ = (Uint8)yuv[2][0];
slouken@11702
   129
slouken@11702
   130
            RGBtoYUV(rgb2, yuv[3], mode, monochrome, luminance);
slouken@11702
   131
            rgb2 += 3;
slouken@11702
   132
            *Y2++ = (Uint8)yuv[3][0];
slouken@11702
   133
slouken@11702
   134
            *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[1][1] + yuv[2][1] + yuv[3][1])/4.0f + 0.5f);
slouken@11702
   135
            U += UV_advance;
slouken@11702
   136
slouken@11702
   137
            *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[1][2] + yuv[2][2] + yuv[3][2])/4.0f + 0.5f);
slouken@11702
   138
            V += UV_advance;
slouken@11702
   139
        }
slouken@11702
   140
        /* Last column */
slouken@11702
   141
        if (x == (w - 1)) {
slouken@11702
   142
            RGBtoYUV(rgb1, yuv[0], mode, monochrome, luminance);
slouken@11702
   143
            rgb1 += 3;
slouken@11702
   144
            *Y1++ = (Uint8)yuv[0][0];
slouken@11702
   145
slouken@11702
   146
            RGBtoYUV(rgb2, yuv[2], mode, monochrome, luminance);
slouken@11702
   147
            rgb2 += 3;
slouken@11702
   148
            *Y2++ = (Uint8)yuv[2][0];
slouken@11702
   149
slouken@11702
   150
            *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[2][1])/2.0f + 0.5f);
slouken@11702
   151
            U += UV_advance;
slouken@11702
   152
slouken@11702
   153
            *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[2][2])/2.0f + 0.5f);
slouken@11702
   154
            V += UV_advance;
slouken@11702
   155
        }
slouken@11702
   156
        Y1 += w;
slouken@11702
   157
        Y2 += w;
slouken@11702
   158
        rgb1 += rgb_row_advance;
slouken@11702
   159
        rgb2 += rgb_row_advance;
slouken@11702
   160
    }
slouken@11702
   161
    /* Last row */
slouken@11702
   162
    if (y == (h - 1)) {
slouken@11702
   163
        for (x = 0; x < (w - 1); x += 2) {
slouken@11702
   164
            RGBtoYUV(rgb1, yuv[0], mode, monochrome, luminance);
slouken@11702
   165
            rgb1 += 3;
slouken@11702
   166
            *Y1++ = (Uint8)yuv[0][0];
slouken@11702
   167
slouken@11702
   168
            RGBtoYUV(rgb1, yuv[1], mode, monochrome, luminance);
slouken@11702
   169
            rgb1 += 3;
slouken@11702
   170
            *Y1++ = (Uint8)yuv[1][0];
slouken@11702
   171
slouken@11702
   172
            *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[1][1])/2.0f + 0.5f);
slouken@11702
   173
            U += UV_advance;
slouken@11702
   174
slouken@11702
   175
            *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[1][2])/2.0f + 0.5f);
slouken@11702
   176
            V += UV_advance;
slouken@11702
   177
        }
slouken@11702
   178
        /* Last column */
slouken@11702
   179
        if (x == (w - 1)) {
slouken@11702
   180
            RGBtoYUV(rgb1, yuv[0], mode, monochrome, luminance);
slouken@11702
   181
            *Y1++ = (Uint8)yuv[0][0];
slouken@11702
   182
slouken@11702
   183
            *U = (Uint8)yuv[0][1];
slouken@11702
   184
            U += UV_advance;
slouken@11702
   185
slouken@11702
   186
            *V = (Uint8)yuv[0][2];
slouken@11702
   187
            V += UV_advance;
slouken@11702
   188
        }
slouken@11702
   189
    }
slouken@11702
   190
}
slouken@11702
   191
slouken@11702
   192
static void ConvertRGBtoPacked4(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, SDL_YUV_CONVERSION_MODE mode, int monochrome, int luminance)
slouken@11702
   193
{
slouken@11702
   194
    int x, y;
slouken@11702
   195
    int yuv[2][3];
slouken@11702
   196
    Uint8 *Y1, *Y2, *U, *V;
slouken@11702
   197
    Uint8 *rgb;
slouken@11702
   198
    int rgb_row_advance = (pitch - w*3);
slouken@11702
   199
slouken@11702
   200
    rgb = src;
slouken@11702
   201
slouken@11702
   202
    switch (format) {
slouken@11702
   203
    case SDL_PIXELFORMAT_YUY2:
slouken@11702
   204
        Y1 = out;
slouken@11702
   205
        U = out+1;
slouken@11702
   206
        Y2 = out+2;
slouken@11702
   207
        V = out+3;
slouken@11702
   208
        break;
slouken@11702
   209
    case SDL_PIXELFORMAT_UYVY:
slouken@11702
   210
        U = out;
slouken@11702
   211
        Y1 = out+1;
slouken@11702
   212
        V = out+2;
slouken@11702
   213
        Y2 = out+3;
slouken@11702
   214
        break;
slouken@11702
   215
    case SDL_PIXELFORMAT_YVYU:
slouken@11702
   216
        Y1 = out;
slouken@11702
   217
        V = out+1;
slouken@11702
   218
        Y2 = out+2;
slouken@11702
   219
        U = out+3;
slouken@11702
   220
        break;
slouken@11702
   221
    default:
slouken@11702
   222
        SDL_assert(!"Unsupported packed YUV format");
slouken@11702
   223
        return;
slouken@11702
   224
    }
slouken@11702
   225
slouken@11702
   226
    for (y = 0; y < h; ++y) {
slouken@11702
   227
        for (x = 0; x < (w - 1); x += 2) {
slouken@11702
   228
            RGBtoYUV(rgb, yuv[0], mode, monochrome, luminance);
slouken@11702
   229
            rgb += 3;
slouken@11702
   230
            *Y1 = (Uint8)yuv[0][0];
slouken@11702
   231
            Y1 += 4;
slouken@11702
   232
slouken@11702
   233
            RGBtoYUV(rgb, yuv[1], mode, monochrome, luminance);
slouken@11702
   234
            rgb += 3;
slouken@11702
   235
            *Y2 = (Uint8)yuv[1][0];
slouken@11702
   236
            Y2 += 4;
slouken@11702
   237
slouken@11702
   238
            *U = (Uint8)SDL_floorf((yuv[0][1] + yuv[1][1])/2.0f + 0.5f);
slouken@11702
   239
            U += 4;
slouken@11702
   240
slouken@11702
   241
            *V = (Uint8)SDL_floorf((yuv[0][2] + yuv[1][2])/2.0f + 0.5f);
slouken@11702
   242
            V += 4;
slouken@11702
   243
        }
slouken@11702
   244
        /* Last column */
slouken@11702
   245
        if (x == (w - 1)) {
slouken@11702
   246
            RGBtoYUV(rgb, yuv[0], mode, monochrome, luminance);
slouken@11702
   247
            rgb += 3;
slouken@11702
   248
            *Y2 = *Y1 = (Uint8)yuv[0][0];
slouken@11702
   249
            Y1 += 4;
slouken@11702
   250
            Y2 += 4;
slouken@11702
   251
slouken@11702
   252
            *U = (Uint8)yuv[0][1];
slouken@11702
   253
            U += 4;
slouken@11702
   254
slouken@11702
   255
            *V = (Uint8)yuv[0][2];
slouken@11702
   256
            V += 4;
slouken@11702
   257
        }
slouken@11702
   258
        rgb += rgb_row_advance;
slouken@11702
   259
    }
slouken@11702
   260
}
slouken@11702
   261
slouken@11702
   262
SDL_bool ConvertRGBtoYUV(Uint32 format, Uint8 *src, int pitch, Uint8 *out, int w, int h, SDL_YUV_CONVERSION_MODE mode, int monochrome, int luminance)
slouken@11702
   263
{
slouken@11702
   264
    switch (format)
slouken@11702
   265
    {
slouken@11702
   266
    case SDL_PIXELFORMAT_YV12:
slouken@11702
   267
    case SDL_PIXELFORMAT_IYUV:
slouken@11702
   268
    case SDL_PIXELFORMAT_NV12:
slouken@11702
   269
    case SDL_PIXELFORMAT_NV21:
slouken@11702
   270
        ConvertRGBtoPlanar2x2(format, src, pitch, out, w, h, mode, monochrome, luminance);
slouken@11702
   271
        return SDL_TRUE;
slouken@11702
   272
    case SDL_PIXELFORMAT_YUY2:
slouken@11702
   273
    case SDL_PIXELFORMAT_UYVY:
slouken@11702
   274
    case SDL_PIXELFORMAT_YVYU:
slouken@11702
   275
        ConvertRGBtoPacked4(format, src, pitch, out, w, h, mode, monochrome, luminance);
slouken@11702
   276
        return SDL_TRUE;
slouken@11702
   277
    default:
slouken@11702
   278
        return SDL_FALSE;
slouken@11702
   279
    }
slouken@11702
   280
}
slouken@11702
   281
slouken@11702
   282
int CalculateYUVPitch(Uint32 format, int width)
slouken@11702
   283
{
slouken@11702
   284
    switch (format)
slouken@11702
   285
    {
slouken@11702
   286
    case SDL_PIXELFORMAT_YV12:
slouken@11702
   287
    case SDL_PIXELFORMAT_IYUV:
slouken@11702
   288
    case SDL_PIXELFORMAT_NV12:
slouken@11702
   289
    case SDL_PIXELFORMAT_NV21:
slouken@11702
   290
        return width;
slouken@11702
   291
    case SDL_PIXELFORMAT_YUY2:
slouken@11702
   292
    case SDL_PIXELFORMAT_UYVY:
slouken@11702
   293
    case SDL_PIXELFORMAT_YVYU:
slouken@11702
   294
        return 4*((width + 1)/2);
slouken@11702
   295
    default:
slouken@11702
   296
        return 0;
slouken@11702
   297
    }
slouken@11702
   298
}
slouken@11702
   299
slouken@11702
   300
/* vi: set ts=4 sw=4 expandtab: */