src/render/SDL_yuv_sw.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 14 Jun 2019 13:56:42 -0700
changeset 12860 0f52dd40abe5
parent 12503 806492103856
permissions -rw-r--r--
Worked around "Undefined symbol: ___isPlatformVersionAtLeast()" link error on Xcode 11 beta
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../SDL_internal.h"
    22 
    23 /* This is the software implementation of the YUV texture support */
    24 
    25 #include "SDL_assert.h"
    26 
    27 #include "SDL_yuv_sw_c.h"
    28 
    29 
    30 SDL_SW_YUVTexture *
    31 SDL_SW_CreateYUVTexture(Uint32 format, int w, int h)
    32 {
    33     SDL_SW_YUVTexture *swdata;
    34 
    35     switch (format) {
    36     case SDL_PIXELFORMAT_YV12:
    37     case SDL_PIXELFORMAT_IYUV:
    38     case SDL_PIXELFORMAT_YUY2:
    39     case SDL_PIXELFORMAT_UYVY:
    40     case SDL_PIXELFORMAT_YVYU:
    41     case SDL_PIXELFORMAT_NV12:
    42     case SDL_PIXELFORMAT_NV21:
    43         break;
    44     default:
    45         SDL_SetError("Unsupported YUV format");
    46         return NULL;
    47     }
    48 
    49     swdata = (SDL_SW_YUVTexture *) SDL_calloc(1, sizeof(*swdata));
    50     if (!swdata) {
    51         SDL_OutOfMemory();
    52         return NULL;
    53     }
    54 
    55     swdata->format = format;
    56     swdata->target_format = SDL_PIXELFORMAT_UNKNOWN;
    57     swdata->w = w;
    58     swdata->h = h;
    59     {
    60         const int sz_plane         = w * h;
    61         const int sz_plane_chroma  = ((w + 1) / 2) * ((h + 1) / 2);
    62         const int sz_plane_packed  = ((w + 1) / 2) * h;
    63         int dst_size = 0;     
    64         switch(format) 
    65         {
    66             case SDL_PIXELFORMAT_YV12: /**< Planar mode: Y + V + U  (3 planes) */
    67             case SDL_PIXELFORMAT_IYUV: /**< Planar mode: Y + U + V  (3 planes) */
    68                 dst_size = sz_plane + sz_plane_chroma + sz_plane_chroma;
    69                 break;
    70 
    71             case SDL_PIXELFORMAT_YUY2: /**< Packed mode: Y0+U0+Y1+V0 (1 plane) */
    72             case SDL_PIXELFORMAT_UYVY: /**< Packed mode: U0+Y0+V0+Y1 (1 plane) */
    73             case SDL_PIXELFORMAT_YVYU: /**< Packed mode: Y0+V0+Y1+U0 (1 plane) */
    74                 dst_size = 4 * sz_plane_packed;
    75                 break;
    76 
    77             case SDL_PIXELFORMAT_NV12: /**< Planar mode: Y + U/V interleaved  (2 planes) */
    78             case SDL_PIXELFORMAT_NV21: /**< Planar mode: Y + V/U interleaved  (2 planes) */
    79                 dst_size = sz_plane + sz_plane_chroma + sz_plane_chroma;
    80                 break;
    81 
    82             default:
    83                 SDL_assert(0 && "We should never get here (caught above)");
    84                 break;
    85         }
    86         swdata->pixels = (Uint8 *) SDL_malloc(dst_size);
    87         if (!swdata->pixels) {
    88             SDL_SW_DestroyYUVTexture(swdata);
    89             SDL_OutOfMemory();
    90             return NULL;
    91         }
    92     }
    93 
    94     /* Find the pitch and offset values for the texture */
    95     switch (format) {
    96     case SDL_PIXELFORMAT_YV12:
    97     case SDL_PIXELFORMAT_IYUV:
    98         swdata->pitches[0] = w;
    99         swdata->pitches[1] = (swdata->pitches[0] + 1) / 2;
   100         swdata->pitches[2] = (swdata->pitches[0] + 1) / 2;
   101         swdata->planes[0] = swdata->pixels;
   102         swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h;
   103         swdata->planes[2] = swdata->planes[1] + swdata->pitches[1] * ((h + 1) / 2);
   104         break;
   105     case SDL_PIXELFORMAT_YUY2:
   106     case SDL_PIXELFORMAT_UYVY:
   107     case SDL_PIXELFORMAT_YVYU:
   108         swdata->pitches[0] = ((w + 1) / 2) * 4;
   109         swdata->planes[0] = swdata->pixels;
   110         break;
   111 
   112     case SDL_PIXELFORMAT_NV12:
   113     case SDL_PIXELFORMAT_NV21:
   114         swdata->pitches[0] = w;
   115         swdata->pitches[1] = 2 * ((swdata->pitches[0] + 1) / 2);
   116         swdata->planes[0] = swdata->pixels;
   117         swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h;
   118         break;
   119 
   120     default:
   121         SDL_assert(0 && "We should never get here (caught above)");
   122         break;
   123     }
   124 
   125     /* We're all done.. */
   126     return (swdata);
   127 }
   128 
   129 int
   130 SDL_SW_QueryYUVTexturePixels(SDL_SW_YUVTexture * swdata, void **pixels,
   131                              int *pitch)
   132 {
   133     *pixels = swdata->planes[0];
   134     *pitch = swdata->pitches[0];
   135     return 0;
   136 }
   137 
   138 int
   139 SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
   140                         const void *pixels, int pitch)
   141 {
   142     switch (swdata->format) {
   143     case SDL_PIXELFORMAT_YV12:
   144     case SDL_PIXELFORMAT_IYUV:
   145         if (rect->x == 0 && rect->y == 0 &&
   146             rect->w == swdata->w && rect->h == swdata->h) {
   147                 SDL_memcpy(swdata->pixels, pixels,
   148                            (swdata->h * swdata->w) + 2* ((swdata->h + 1) /2) * ((swdata->w + 1) / 2));
   149         } else {
   150             Uint8 *src, *dst;
   151             int row;
   152             size_t length;
   153 
   154             /* Copy the Y plane */
   155             src = (Uint8 *) pixels;
   156             dst = swdata->pixels + rect->y * swdata->w + rect->x;
   157             length = rect->w;
   158             for (row = 0; row < rect->h; ++row) {
   159                 SDL_memcpy(dst, src, length);
   160                 src += pitch;
   161                 dst += swdata->w;
   162             }
   163             
   164             /* Copy the next plane */
   165             src = (Uint8 *) pixels + rect->h * pitch;
   166             dst = swdata->pixels + swdata->h * swdata->w;
   167             dst += rect->y/2 * ((swdata->w + 1) / 2) + rect->x/2;
   168             length = (rect->w + 1) / 2;
   169             for (row = 0; row < (rect->h + 1)/2; ++row) {
   170                 SDL_memcpy(dst, src, length);
   171                 src += (pitch + 1)/2;
   172                 dst += (swdata->w + 1)/2;
   173             }
   174 
   175             /* Copy the next plane */
   176             src = (Uint8 *) pixels + rect->h * pitch + ((rect->h + 1) / 2) * ((pitch + 1) / 2);
   177             dst = swdata->pixels + swdata->h * swdata->w +
   178                   ((swdata->h + 1)/2) * ((swdata->w+1) / 2);
   179             dst += rect->y/2 * ((swdata->w + 1)/2) + rect->x/2;
   180             length = (rect->w + 1) / 2;
   181             for (row = 0; row < (rect->h + 1)/2; ++row) {
   182                 SDL_memcpy(dst, src, length);
   183                 src += (pitch + 1)/2;
   184                 dst += (swdata->w + 1)/2;
   185             }
   186         }
   187         break;
   188     case SDL_PIXELFORMAT_YUY2:
   189     case SDL_PIXELFORMAT_UYVY:
   190     case SDL_PIXELFORMAT_YVYU:
   191         {
   192             Uint8 *src, *dst;
   193             int row;
   194             size_t length;
   195 
   196             src = (Uint8 *) pixels;
   197             dst =
   198                 swdata->planes[0] + rect->y * swdata->pitches[0] +
   199                 rect->x * 2;
   200             length = 4 * ((rect->w + 1) / 2);
   201             for (row = 0; row < rect->h; ++row) {
   202                 SDL_memcpy(dst, src, length);
   203                 src += pitch;
   204                 dst += swdata->pitches[0];
   205             }
   206         }
   207         break;
   208     case SDL_PIXELFORMAT_NV12:
   209     case SDL_PIXELFORMAT_NV21:
   210         {
   211             if (rect->x == 0 && rect->y == 0 && rect->w == swdata->w && rect->h == swdata->h) {
   212                 SDL_memcpy(swdata->pixels, pixels,
   213                         (swdata->h * swdata->w) + 2* ((swdata->h + 1) /2) * ((swdata->w + 1) / 2));
   214             } else {
   215 
   216                 Uint8 *src, *dst;
   217                 int row;
   218                 size_t length;
   219 
   220                 /* Copy the Y plane */
   221                 src = (Uint8 *) pixels;
   222                 dst = swdata->pixels + rect->y * swdata->w + rect->x;
   223                 length = rect->w;
   224                 for (row = 0; row < rect->h; ++row) {
   225                     SDL_memcpy(dst, src, length);
   226                     src += pitch;
   227                     dst += swdata->w;
   228                 }
   229                 
   230                 /* Copy the next plane */
   231                 src = (Uint8 *) pixels + rect->h * pitch;
   232                 dst = swdata->pixels + swdata->h * swdata->w;
   233                 dst += 2 * ((rect->y + 1)/2) * ((swdata->w + 1) / 2) + 2 * (rect->x/2);
   234                 length = 2 * ((rect->w + 1) / 2);
   235                 for (row = 0; row < (rect->h + 1)/2; ++row) {
   236                     SDL_memcpy(dst, src, length);
   237                     src += 2 * ((pitch + 1)/2);
   238                     dst += 2 * ((swdata->w + 1)/2);
   239                 }
   240             }
   241         }
   242     }
   243     return 0;
   244 }
   245 
   246 int
   247 SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
   248                               const Uint8 *Yplane, int Ypitch,
   249                               const Uint8 *Uplane, int Upitch,
   250                               const Uint8 *Vplane, int Vpitch)
   251 {
   252     const Uint8 *src;
   253     Uint8 *dst;
   254     int row;
   255     size_t length;
   256 
   257     /* Copy the Y plane */
   258     src = Yplane;
   259     dst = swdata->pixels + rect->y * swdata->w + rect->x;
   260     length = rect->w;
   261     for (row = 0; row < rect->h; ++row) {
   262         SDL_memcpy(dst, src, length);
   263         src += Ypitch;
   264         dst += swdata->w;
   265     }
   266 
   267     /* Copy the U plane */
   268     src = Uplane;
   269     if (swdata->format == SDL_PIXELFORMAT_IYUV) {
   270         dst = swdata->pixels + swdata->h * swdata->w;
   271     } else {
   272         dst = swdata->pixels + swdata->h * swdata->w +
   273               ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2);
   274     }
   275     dst += rect->y/2 * ((swdata->w + 1)/2) + rect->x/2;
   276     length = (rect->w + 1) / 2;
   277     for (row = 0; row < (rect->h + 1)/2; ++row) {
   278         SDL_memcpy(dst, src, length);
   279         src += Upitch;
   280         dst += (swdata->w + 1)/2;
   281     }
   282 
   283     /* Copy the V plane */
   284     src = Vplane;
   285     if (swdata->format == SDL_PIXELFORMAT_YV12) {
   286         dst = swdata->pixels + swdata->h * swdata->w;
   287     } else {
   288         dst = swdata->pixels + swdata->h * swdata->w +
   289               ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2);
   290     }
   291     dst += rect->y/2 * ((swdata->w + 1)/2) + rect->x/2;
   292     length = (rect->w + 1) / 2;
   293     for (row = 0; row < (rect->h + 1)/2; ++row) {
   294         SDL_memcpy(dst, src, length);
   295         src += Vpitch;
   296         dst += (swdata->w + 1)/2;
   297     }
   298     return 0;
   299 }
   300 
   301 int
   302 SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
   303                       void **pixels, int *pitch)
   304 {
   305     switch (swdata->format) {
   306     case SDL_PIXELFORMAT_YV12:
   307     case SDL_PIXELFORMAT_IYUV:
   308     case SDL_PIXELFORMAT_NV12:
   309     case SDL_PIXELFORMAT_NV21:
   310         if (rect
   311             && (rect->x != 0 || rect->y != 0 || rect->w != swdata->w
   312                 || rect->h != swdata->h)) {
   313             return SDL_SetError
   314                 ("YV12, IYUV, NV12, NV21 textures only support full surface locks");
   315         }
   316         break;
   317     }
   318 
   319     if (rect) {
   320         *pixels = swdata->planes[0] + rect->y * swdata->pitches[0] + rect->x * 2;
   321     } else {
   322         *pixels = swdata->planes[0];
   323     }
   324     *pitch = swdata->pitches[0];
   325     return 0;
   326 }
   327 
   328 void
   329 SDL_SW_UnlockYUVTexture(SDL_SW_YUVTexture * swdata)
   330 {
   331 }
   332 
   333 int
   334 SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture * swdata, const SDL_Rect * srcrect,
   335                     Uint32 target_format, int w, int h, void *pixels,
   336                     int pitch)
   337 {
   338     int stretch;
   339 
   340     /* Make sure we're set up to display in the desired format */
   341     if (target_format != swdata->target_format && swdata->display) {
   342         SDL_FreeSurface(swdata->display);
   343         swdata->display = NULL;
   344     }
   345 
   346     stretch = 0;
   347     if (srcrect->x || srcrect->y || srcrect->w < swdata->w || srcrect->h < swdata->h) {
   348         /* The source rectangle has been clipped.
   349            Using a scratch surface is easier than adding clipped
   350            source support to all the blitters, plus that would
   351            slow them down in the general unclipped case.
   352          */
   353         stretch = 1;
   354     } else if ((srcrect->w != w) || (srcrect->h != h)) {
   355         stretch = 1;
   356     }
   357     if (stretch) {
   358         int bpp;
   359         Uint32 Rmask, Gmask, Bmask, Amask;
   360 
   361         if (swdata->display) {
   362             swdata->display->w = w;
   363             swdata->display->h = h;
   364             swdata->display->pixels = pixels;
   365             swdata->display->pitch = pitch;
   366         } else {
   367             /* This must have succeeded in SDL_SW_SetupYUVDisplay() earlier */
   368             SDL_PixelFormatEnumToMasks(target_format, &bpp, &Rmask, &Gmask,
   369                                        &Bmask, &Amask);
   370             swdata->display =
   371                 SDL_CreateRGBSurfaceFrom(pixels, w, h, bpp, pitch, Rmask,
   372                                          Gmask, Bmask, Amask);
   373             if (!swdata->display) {
   374                 return (-1);
   375             }
   376         }
   377         if (!swdata->stretch) {
   378             /* This must have succeeded in SDL_SW_SetupYUVDisplay() earlier */
   379             SDL_PixelFormatEnumToMasks(target_format, &bpp, &Rmask, &Gmask,
   380                                        &Bmask, &Amask);
   381             swdata->stretch =
   382                 SDL_CreateRGBSurface(0, swdata->w, swdata->h, bpp, Rmask,
   383                                      Gmask, Bmask, Amask);
   384             if (!swdata->stretch) {
   385                 return (-1);
   386             }
   387         }
   388         pixels = swdata->stretch->pixels;
   389         pitch = swdata->stretch->pitch;
   390     }
   391     if (SDL_ConvertPixels(swdata->w, swdata->h, swdata->format,
   392                           swdata->planes[0], swdata->pitches[0], 
   393                           target_format, pixels, pitch) < 0) {
   394         return -1;
   395     }
   396     if (stretch) {
   397         SDL_Rect rect = *srcrect;
   398         SDL_SoftStretch(swdata->stretch, &rect, swdata->display, NULL);
   399     }
   400     return 0;
   401 }
   402 
   403 void
   404 SDL_SW_DestroyYUVTexture(SDL_SW_YUVTexture * swdata)
   405 {
   406     if (swdata) {
   407         SDL_free(swdata->pixels);
   408         SDL_FreeSurface(swdata->stretch);
   409         SDL_FreeSurface(swdata->display);
   410         SDL_free(swdata);
   411     }
   412 }
   413 
   414 /* vi: set ts=4 sw=4 expandtab: */