test/testyuv_cvt.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 07 Dec 2017 16:08:47 -0800
changeset 11731 30f337dc8c74
parent 11702 cf166abbde4a
child 11811 5d94cb6b24d3
permissions -rw-r--r--
Added iOS and OSX 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: */