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