test/testyuv_cvt.c
changeset 11702 cf166abbde4a
child 11811 5d94cb6b24d3
equal deleted inserted replaced
11701:d131f3193794 11702:cf166abbde4a
       
     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: */