sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

testyuv_cvt.c (8503B)


      1 /*
      2   Copyright (C) 1997-2020 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: */