test/testyuv_cvt.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 27 Jan 2018 12:05:26 -0800
changeset 11836 a42b155124a3
parent 11811 5d94cb6b24d3
child 12503 806492103856
permissions -rw-r--r--
Fixed bug 4065 - SDL_wave.c fail to compile in armeabi with ndk r16b

Sylvain

armeabi is almost deprecated for android-ndk higher that r13b.
either it doesn't compile (ICE), or it executes wrongly (using long long for instance).

android people advices to use armeabi-v7a (or use r13b).
slouken@11702
     1
/*
slouken@11811
     2
  Copyright (C) 1997-2018 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: */