src/video/SDL_yuv.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 24 Sep 2018 11:49:25 -0700
changeset 12201 8bdc4d340419
parent 11811 5d94cb6b24d3
child 12242 df7260f149f2
permissions -rw-r--r--
Fixed whitespace
slouken@11702
     1
/*
slouken@11702
     2
  Simple DirectMedia Layer
slouken@11811
     3
  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
slouken@11702
     4
slouken@11702
     5
  This software is provided 'as-is', without any express or implied
slouken@11702
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@11702
     7
  arising from the use of this software.
slouken@11702
     8
slouken@11702
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@11702
    10
  including commercial applications, and to alter it and redistribute it
slouken@11702
    11
  freely, subject to the following restrictions:
slouken@11702
    12
slouken@11702
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@11702
    14
     claim that you wrote the original software. If you use this software
slouken@11702
    15
     in a product, an acknowledgment in the product documentation would be
slouken@11702
    16
     appreciated but is not required.
slouken@11702
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@11702
    18
     misrepresented as being the original software.
slouken@11702
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@11702
    20
*/
slouken@11702
    21
#include "../SDL_internal.h"
slouken@11702
    22
slouken@11702
    23
#include "SDL_endian.h"
slouken@11702
    24
#include "SDL_video.h"
slouken@11702
    25
#include "SDL_pixels_c.h"
slouken@11702
    26
slouken@11702
    27
#include "yuv2rgb/yuv_rgb.h"
slouken@11702
    28
slouken@11702
    29
#define SDL_YUV_SD_THRESHOLD    576
slouken@11702
    30
slouken@11702
    31
slouken@11702
    32
static SDL_YUV_CONVERSION_MODE SDL_YUV_ConversionMode = SDL_YUV_CONVERSION_BT601;
slouken@11702
    33
slouken@11702
    34
slouken@11702
    35
void SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_MODE mode)
slouken@11702
    36
{
slouken@11702
    37
    SDL_YUV_ConversionMode = mode;
slouken@11702
    38
}
slouken@11702
    39
slouken@11702
    40
SDL_YUV_CONVERSION_MODE SDL_GetYUVConversionMode()
slouken@11702
    41
{
slouken@11702
    42
    return SDL_YUV_ConversionMode;
slouken@11702
    43
}
slouken@11702
    44
slouken@11702
    45
SDL_YUV_CONVERSION_MODE SDL_GetYUVConversionModeForResolution(int width, int height)
slouken@11702
    46
{
slouken@11702
    47
    SDL_YUV_CONVERSION_MODE mode = SDL_GetYUVConversionMode();
slouken@11702
    48
    if (mode == SDL_YUV_CONVERSION_AUTOMATIC) {
slouken@11702
    49
        if (height <= SDL_YUV_SD_THRESHOLD) {
slouken@11702
    50
            mode = SDL_YUV_CONVERSION_BT601;
slouken@11702
    51
        } else {
slouken@11702
    52
            mode = SDL_YUV_CONVERSION_BT709;
slouken@11702
    53
        }
slouken@11702
    54
    }
slouken@11702
    55
    return mode;
slouken@11702
    56
}
slouken@11702
    57
slouken@11702
    58
static int GetYUVConversionType(int width, int height, YCbCrType *yuv_type)
slouken@11702
    59
{
slouken@11702
    60
    switch (SDL_GetYUVConversionModeForResolution(width, height)) {
slouken@11702
    61
    case SDL_YUV_CONVERSION_JPEG:
slouken@11702
    62
        *yuv_type = YCBCR_JPEG;
slouken@11702
    63
        break;
slouken@11702
    64
    case SDL_YUV_CONVERSION_BT601:
slouken@11702
    65
        *yuv_type = YCBCR_601;
slouken@11702
    66
        break;
slouken@11702
    67
    case SDL_YUV_CONVERSION_BT709:
slouken@11702
    68
        *yuv_type = YCBCR_709;
slouken@11702
    69
        break;
slouken@11702
    70
    default:
slouken@11702
    71
        return SDL_SetError("Unexpected YUV conversion mode");
slouken@11702
    72
    }
slouken@11702
    73
    return 0;
slouken@11702
    74
}
slouken@11702
    75
slouken@11702
    76
static SDL_bool IsPlanar2x2Format(Uint32 format)
slouken@11702
    77
{
slouken@11702
    78
    return (format == SDL_PIXELFORMAT_YV12 ||
slouken@11702
    79
            format == SDL_PIXELFORMAT_IYUV ||
slouken@11702
    80
            format == SDL_PIXELFORMAT_NV12 ||
slouken@11702
    81
            format == SDL_PIXELFORMAT_NV21);
slouken@11702
    82
}
slouken@11702
    83
slouken@11702
    84
static SDL_bool IsPacked4Format(Uint32 format)
slouken@11702
    85
{
slouken@11702
    86
    return (format == SDL_PIXELFORMAT_YUY2 ||
slouken@11702
    87
            format == SDL_PIXELFORMAT_UYVY ||
slouken@11702
    88
            format == SDL_PIXELFORMAT_YVYU);
slouken@11702
    89
}
slouken@11702
    90
slouken@11702
    91
static int GetYUVPlanes(int width, int height, Uint32 format, const void *yuv, int yuv_pitch,
slouken@12201
    92
                        const Uint8 **y, const Uint8 **u, const Uint8 **v, Uint32 *y_stride, Uint32 *uv_stride)
slouken@11702
    93
{
slouken@12201
    94
    const Uint8 *planes[3] = { NULL, NULL, NULL };
slouken@12201
    95
    int pitches[3] = { 0, 0, 0 };
slouken@11702
    96
slouken@11702
    97
    switch (format) {
slouken@11702
    98
    case SDL_PIXELFORMAT_YV12:
slouken@11702
    99
    case SDL_PIXELFORMAT_IYUV:
slouken@11702
   100
        pitches[0] = yuv_pitch;
slouken@11702
   101
        pitches[1] = (pitches[0] + 1) / 2;
slouken@11702
   102
        pitches[2] = (pitches[0] + 1) / 2;
slouken@11702
   103
        planes[0] = (const Uint8 *)yuv;
slouken@11702
   104
        planes[1] = planes[0] + pitches[0] * height;
slouken@11702
   105
        planes[2] = planes[1] + pitches[1] * ((height + 1) / 2);
slouken@11702
   106
        break;
slouken@11702
   107
    case SDL_PIXELFORMAT_YUY2:
slouken@11702
   108
    case SDL_PIXELFORMAT_UYVY:
slouken@11702
   109
    case SDL_PIXELFORMAT_YVYU:
slouken@11702
   110
        pitches[0] = yuv_pitch;
slouken@11702
   111
        planes[0] = (const Uint8 *)yuv;
slouken@11702
   112
        break;
slouken@11702
   113
    case SDL_PIXELFORMAT_NV12:
slouken@11702
   114
    case SDL_PIXELFORMAT_NV21:
slouken@11702
   115
        pitches[0] = yuv_pitch;
slouken@11702
   116
        pitches[1] = 2 * ((pitches[0] + 1) / 2);
slouken@11702
   117
        planes[0] = (const Uint8 *)yuv;
slouken@11702
   118
        planes[1] = planes[0] + pitches[0] * height;
slouken@11702
   119
        break;
slouken@11702
   120
    default:
slouken@11702
   121
        return SDL_SetError("GetYUVPlanes(): Unsupported YUV format: %s", SDL_GetPixelFormatName(format));
slouken@11702
   122
    }
slouken@11702
   123
slouken@11702
   124
    switch (format) {
slouken@11702
   125
    case SDL_PIXELFORMAT_YV12:
slouken@11702
   126
        *y = planes[0];
slouken@11702
   127
        *y_stride = pitches[0];
slouken@11702
   128
        *v = planes[1];
slouken@11702
   129
        *u = planes[2];
slouken@11702
   130
        *uv_stride = pitches[1];
slouken@11702
   131
        break;
slouken@11702
   132
    case SDL_PIXELFORMAT_IYUV:
slouken@11702
   133
        *y = planes[0];
slouken@11702
   134
        *y_stride = pitches[0];
slouken@11702
   135
        *v = planes[2];
slouken@11702
   136
        *u = planes[1];
slouken@11702
   137
        *uv_stride = pitches[1];
slouken@11702
   138
        break;
slouken@11702
   139
    case SDL_PIXELFORMAT_YUY2:
slouken@11702
   140
        *y = planes[0];
slouken@11702
   141
        *y_stride = pitches[0];
slouken@11702
   142
        *v = *y + 3;
slouken@11702
   143
        *u = *y + 1;
slouken@11702
   144
        *uv_stride = pitches[0];
slouken@11702
   145
        break;
slouken@11702
   146
    case SDL_PIXELFORMAT_UYVY:
slouken@11702
   147
        *y = planes[0] + 1;
slouken@11702
   148
        *y_stride = pitches[0];
slouken@11702
   149
        *v = *y + 1;
slouken@11702
   150
        *u = *y - 1;
slouken@11702
   151
        *uv_stride = pitches[0];
slouken@11702
   152
        break;
slouken@11702
   153
    case SDL_PIXELFORMAT_YVYU:
slouken@11702
   154
        *y = planes[0];
slouken@11702
   155
        *y_stride = pitches[0];
slouken@11702
   156
        *v = *y + 1;
slouken@11702
   157
        *u = *y + 3;
slouken@11702
   158
        *uv_stride = pitches[0];
slouken@11702
   159
        break;
slouken@11702
   160
    case SDL_PIXELFORMAT_NV12:
slouken@11702
   161
        *y = planes[0];
slouken@11702
   162
        *y_stride = pitches[0];
slouken@11702
   163
        *u = planes[1];
slouken@11702
   164
        *v = *u + 1;
slouken@11702
   165
        *uv_stride = pitches[1];
slouken@11702
   166
        break;
slouken@11702
   167
    case SDL_PIXELFORMAT_NV21:
slouken@11702
   168
        *y = planes[0];
slouken@11702
   169
        *y_stride = pitches[0];
slouken@11702
   170
        *v = planes[1];
slouken@11702
   171
        *u = *v + 1;
slouken@11702
   172
        *uv_stride = pitches[1];
slouken@11702
   173
        break;
slouken@11702
   174
    default:
slouken@11702
   175
        /* Should have caught this above */
slouken@11702
   176
        return SDL_SetError("GetYUVPlanes[2]: Unsupported YUV format: %s", SDL_GetPixelFormatName(format));
slouken@11702
   177
    }
slouken@11702
   178
    return 0;
slouken@11702
   179
}
slouken@11702
   180
slouken@11702
   181
static SDL_bool yuv_rgb_sse(
slouken@11702
   182
    Uint32 src_format, Uint32 dst_format,
slouken@12201
   183
    Uint32 width, Uint32 height, 
slouken@12201
   184
    const Uint8 *y, const Uint8 *u, const Uint8 *v, Uint32 y_stride, Uint32 uv_stride, 
slouken@12201
   185
    Uint8 *rgb, Uint32 rgb_stride, 
slouken@12201
   186
    YCbCrType yuv_type)
slouken@11702
   187
{
slouken@11702
   188
#ifdef __SSE2__
slouken@11702
   189
    if (!SDL_HasSSE2()) {
slouken@11702
   190
        return SDL_FALSE;
slouken@11702
   191
    }
slouken@11702
   192
slouken@11702
   193
    if (src_format == SDL_PIXELFORMAT_YV12 ||
slouken@11702
   194
        src_format == SDL_PIXELFORMAT_IYUV) {
slouken@11702
   195
slouken@11702
   196
        switch (dst_format) {
slouken@11702
   197
        case SDL_PIXELFORMAT_RGB565:
slouken@11702
   198
            yuv420_rgb565_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   199
            return SDL_TRUE;
slouken@11702
   200
        case SDL_PIXELFORMAT_RGB24:
slouken@11702
   201
            yuv420_rgb24_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   202
            return SDL_TRUE;
slouken@11702
   203
        case SDL_PIXELFORMAT_RGBX8888:
slouken@11702
   204
        case SDL_PIXELFORMAT_RGBA8888:
slouken@11702
   205
            yuv420_rgba_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   206
            return SDL_TRUE;
slouken@11702
   207
        case SDL_PIXELFORMAT_BGRX8888:
slouken@11702
   208
        case SDL_PIXELFORMAT_BGRA8888:
slouken@11702
   209
            yuv420_bgra_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   210
            return SDL_TRUE;
slouken@11702
   211
        case SDL_PIXELFORMAT_RGB888:
slouken@11702
   212
        case SDL_PIXELFORMAT_ARGB8888:
slouken@11702
   213
            yuv420_argb_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   214
            return SDL_TRUE;
slouken@11702
   215
        case SDL_PIXELFORMAT_BGR888:
slouken@11702
   216
        case SDL_PIXELFORMAT_ABGR8888:
slouken@11705
   217
            yuv420_abgr_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   218
            return SDL_TRUE;
slouken@11702
   219
        default:
slouken@11702
   220
            break;
slouken@11702
   221
        }
slouken@11702
   222
    }
slouken@11702
   223
slouken@11702
   224
    if (src_format == SDL_PIXELFORMAT_YUY2 ||
slouken@11702
   225
        src_format == SDL_PIXELFORMAT_UYVY ||
slouken@11702
   226
        src_format == SDL_PIXELFORMAT_YVYU) {
slouken@11702
   227
slouken@11702
   228
        switch (dst_format) {
slouken@11702
   229
        case SDL_PIXELFORMAT_RGB565:
slouken@11702
   230
            yuv422_rgb565_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   231
            return SDL_TRUE;
slouken@11702
   232
        case SDL_PIXELFORMAT_RGB24:
slouken@11702
   233
            yuv422_rgb24_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   234
            return SDL_TRUE;
slouken@11702
   235
        case SDL_PIXELFORMAT_RGBX8888:
slouken@11702
   236
        case SDL_PIXELFORMAT_RGBA8888:
slouken@11702
   237
            yuv422_rgba_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   238
            return SDL_TRUE;
slouken@11702
   239
        case SDL_PIXELFORMAT_BGRX8888:
slouken@11702
   240
        case SDL_PIXELFORMAT_BGRA8888:
slouken@11702
   241
            yuv422_bgra_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   242
            return SDL_TRUE;
slouken@11702
   243
        case SDL_PIXELFORMAT_RGB888:
slouken@11702
   244
        case SDL_PIXELFORMAT_ARGB8888:
slouken@11702
   245
            yuv422_argb_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   246
            return SDL_TRUE;
slouken@11702
   247
        case SDL_PIXELFORMAT_BGR888:
slouken@11702
   248
        case SDL_PIXELFORMAT_ABGR8888:
slouken@11705
   249
            yuv422_abgr_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   250
            return SDL_TRUE;
slouken@11702
   251
        default:
slouken@11702
   252
            break;
slouken@11702
   253
        }
slouken@11702
   254
    }
slouken@11702
   255
slouken@11702
   256
    if (src_format == SDL_PIXELFORMAT_NV12 ||
slouken@11702
   257
        src_format == SDL_PIXELFORMAT_NV21) {
slouken@11702
   258
slouken@11702
   259
        switch (dst_format) {
slouken@11702
   260
        case SDL_PIXELFORMAT_RGB565:
slouken@11702
   261
            yuvnv12_rgb565_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   262
            return SDL_TRUE;
slouken@11702
   263
        case SDL_PIXELFORMAT_RGB24:
slouken@11702
   264
            yuvnv12_rgb24_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   265
            return SDL_TRUE;
slouken@11702
   266
        case SDL_PIXELFORMAT_RGBX8888:
slouken@11702
   267
        case SDL_PIXELFORMAT_RGBA8888:
slouken@11702
   268
            yuvnv12_rgba_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   269
            return SDL_TRUE;
slouken@11702
   270
        case SDL_PIXELFORMAT_BGRX8888:
slouken@11702
   271
        case SDL_PIXELFORMAT_BGRA8888:
slouken@11702
   272
            yuvnv12_bgra_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   273
            return SDL_TRUE;
slouken@11702
   274
        case SDL_PIXELFORMAT_RGB888:
slouken@11702
   275
        case SDL_PIXELFORMAT_ARGB8888:
slouken@11702
   276
            yuvnv12_argb_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   277
            return SDL_TRUE;
slouken@11702
   278
        case SDL_PIXELFORMAT_BGR888:
slouken@11702
   279
        case SDL_PIXELFORMAT_ABGR8888:
slouken@11705
   280
            yuvnv12_abgr_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   281
            return SDL_TRUE;
slouken@11702
   282
        default:
slouken@11702
   283
            break;
slouken@11702
   284
        }
slouken@11702
   285
    }
slouken@11702
   286
#endif
slouken@11702
   287
    return SDL_FALSE;
slouken@11702
   288
}
slouken@11702
   289
slouken@11702
   290
static SDL_bool yuv_rgb_std(
slouken@11702
   291
    Uint32 src_format, Uint32 dst_format,
slouken@12201
   292
    Uint32 width, Uint32 height, 
slouken@12201
   293
    const Uint8 *y, const Uint8 *u, const Uint8 *v, Uint32 y_stride, Uint32 uv_stride, 
slouken@12201
   294
    Uint8 *rgb, Uint32 rgb_stride, 
slouken@12201
   295
    YCbCrType yuv_type)
slouken@11702
   296
{
slouken@11702
   297
    if (src_format == SDL_PIXELFORMAT_YV12 ||
slouken@11702
   298
        src_format == SDL_PIXELFORMAT_IYUV) {
slouken@11702
   299
slouken@11702
   300
        switch (dst_format) {
slouken@11702
   301
        case SDL_PIXELFORMAT_RGB565:
slouken@11702
   302
            yuv420_rgb565_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   303
            return SDL_TRUE;
slouken@11702
   304
        case SDL_PIXELFORMAT_RGB24:
slouken@11702
   305
            yuv420_rgb24_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   306
            return SDL_TRUE;
slouken@11702
   307
        case SDL_PIXELFORMAT_RGBX8888:
slouken@11702
   308
        case SDL_PIXELFORMAT_RGBA8888:
slouken@11702
   309
            yuv420_rgba_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   310
            return SDL_TRUE;
slouken@11702
   311
        case SDL_PIXELFORMAT_BGRX8888:
slouken@11702
   312
        case SDL_PIXELFORMAT_BGRA8888:
slouken@11702
   313
            yuv420_bgra_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   314
            return SDL_TRUE;
slouken@11702
   315
        case SDL_PIXELFORMAT_RGB888:
slouken@11702
   316
        case SDL_PIXELFORMAT_ARGB8888:
slouken@11702
   317
            yuv420_argb_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   318
            return SDL_TRUE;
slouken@11702
   319
        case SDL_PIXELFORMAT_BGR888:
slouken@11702
   320
        case SDL_PIXELFORMAT_ABGR8888:
slouken@11705
   321
            yuv420_abgr_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   322
            return SDL_TRUE;
slouken@11702
   323
        default:
slouken@11702
   324
            break;
slouken@11702
   325
        }
slouken@11702
   326
    }
slouken@11702
   327
slouken@11702
   328
    if (src_format == SDL_PIXELFORMAT_YUY2 ||
slouken@11702
   329
        src_format == SDL_PIXELFORMAT_UYVY ||
slouken@11702
   330
        src_format == SDL_PIXELFORMAT_YVYU) {
slouken@11702
   331
slouken@11702
   332
        switch (dst_format) {
slouken@11702
   333
        case SDL_PIXELFORMAT_RGB565:
slouken@11702
   334
            yuv422_rgb565_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   335
            return SDL_TRUE;
slouken@11702
   336
        case SDL_PIXELFORMAT_RGB24:
slouken@11702
   337
            yuv422_rgb24_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   338
            return SDL_TRUE;
slouken@11702
   339
        case SDL_PIXELFORMAT_RGBX8888:
slouken@11702
   340
        case SDL_PIXELFORMAT_RGBA8888:
slouken@11702
   341
            yuv422_rgba_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   342
            return SDL_TRUE;
slouken@11702
   343
        case SDL_PIXELFORMAT_BGRX8888:
slouken@11702
   344
        case SDL_PIXELFORMAT_BGRA8888:
slouken@11702
   345
            yuv422_bgra_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   346
            return SDL_TRUE;
slouken@11702
   347
        case SDL_PIXELFORMAT_RGB888:
slouken@11702
   348
        case SDL_PIXELFORMAT_ARGB8888:
slouken@11702
   349
            yuv422_argb_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   350
            return SDL_TRUE;
slouken@11702
   351
        case SDL_PIXELFORMAT_BGR888:
slouken@11702
   352
        case SDL_PIXELFORMAT_ABGR8888:
slouken@11705
   353
            yuv422_abgr_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   354
            return SDL_TRUE;
slouken@11702
   355
        default:
slouken@11702
   356
            break;
slouken@11702
   357
        }
slouken@11702
   358
    }
slouken@11702
   359
slouken@11702
   360
    if (src_format == SDL_PIXELFORMAT_NV12 ||
slouken@11702
   361
        src_format == SDL_PIXELFORMAT_NV21) {
slouken@11702
   362
slouken@11702
   363
        switch (dst_format) {
slouken@11702
   364
        case SDL_PIXELFORMAT_RGB565:
slouken@11702
   365
            yuvnv12_rgb565_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   366
            return SDL_TRUE;
slouken@11702
   367
        case SDL_PIXELFORMAT_RGB24:
slouken@11702
   368
            yuvnv12_rgb24_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   369
            return SDL_TRUE;
slouken@11702
   370
        case SDL_PIXELFORMAT_RGBX8888:
slouken@11702
   371
        case SDL_PIXELFORMAT_RGBA8888:
slouken@11702
   372
            yuvnv12_rgba_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   373
            return SDL_TRUE;
slouken@11702
   374
        case SDL_PIXELFORMAT_BGRX8888:
slouken@11702
   375
        case SDL_PIXELFORMAT_BGRA8888:
slouken@11702
   376
            yuvnv12_bgra_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   377
            return SDL_TRUE;
slouken@11702
   378
        case SDL_PIXELFORMAT_RGB888:
slouken@11702
   379
        case SDL_PIXELFORMAT_ARGB8888:
slouken@11702
   380
            yuvnv12_argb_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   381
            return SDL_TRUE;
slouken@11702
   382
        case SDL_PIXELFORMAT_BGR888:
slouken@11702
   383
        case SDL_PIXELFORMAT_ABGR8888:
slouken@11705
   384
            yuvnv12_abgr_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type);
slouken@11702
   385
            return SDL_TRUE;
slouken@11702
   386
        default:
slouken@11702
   387
            break;
slouken@11702
   388
        }
slouken@11702
   389
    }
slouken@11702
   390
    return SDL_FALSE;
slouken@11702
   391
}
slouken@11702
   392
slouken@11702
   393
int
slouken@11702
   394
SDL_ConvertPixels_YUV_to_RGB(int width, int height,
slouken@11702
   395
         Uint32 src_format, const void *src, int src_pitch,
slouken@11702
   396
         Uint32 dst_format, void *dst, int dst_pitch)
slouken@11702
   397
{
slouken@12201
   398
    const Uint8 *y = NULL;
slouken@11712
   399
    const Uint8 *u = NULL;
slouken@11712
   400
    const Uint8 *v = NULL;
slouken@11712
   401
    Uint32 y_stride = 0;
slouken@11712
   402
    Uint32 uv_stride = 0;
slouken@11712
   403
    YCbCrType yuv_type = YCBCR_601;
slouken@11702
   404
slouken@11702
   405
    if (GetYUVPlanes(width, height, src_format, src, src_pitch, &y, &u, &v, &y_stride, &uv_stride) < 0) {
slouken@11702
   406
        return -1;
slouken@11702
   407
    }
slouken@11702
   408
slouken@11702
   409
    if (GetYUVConversionType(width, height, &yuv_type) < 0) {
slouken@11702
   410
        return -1;
slouken@11702
   411
    }
slouken@11702
   412
slouken@11702
   413
    if (yuv_rgb_sse(src_format, dst_format, width, height, y, u, v, y_stride, uv_stride, (Uint8*)dst, dst_pitch, yuv_type)) {
slouken@11702
   414
        return 0;
slouken@11702
   415
    }
slouken@11702
   416
slouken@11702
   417
    if (yuv_rgb_std(src_format, dst_format, width, height, y, u, v, y_stride, uv_stride, (Uint8*)dst, dst_pitch, yuv_type)) {
slouken@11702
   418
        return 0;
slouken@11702
   419
    }
slouken@11702
   420
slouken@11702
   421
    /* No fast path for the RGB format, instead convert using an intermediate buffer */
slouken@11702
   422
    if (dst_format != SDL_PIXELFORMAT_ARGB8888) {
slouken@11702
   423
        int ret;
slouken@11702
   424
        void *tmp;
slouken@11702
   425
        int tmp_pitch = (width * sizeof(Uint32));
slouken@11702
   426
slouken@11702
   427
        tmp = SDL_malloc(tmp_pitch * height);
slouken@11702
   428
        if (tmp == NULL) {
slouken@11702
   429
            return SDL_OutOfMemory();
slouken@11702
   430
        }
slouken@11702
   431
slouken@11702
   432
        /* convert src/src_format to tmp/ARGB8888 */
slouken@11702
   433
        ret = SDL_ConvertPixels_YUV_to_RGB(width, height, src_format, src, src_pitch, SDL_PIXELFORMAT_ARGB8888, tmp, tmp_pitch);
slouken@11702
   434
        if (ret < 0) {
slouken@11702
   435
            SDL_free(tmp);
slouken@11702
   436
            return ret;
slouken@11702
   437
        }
slouken@11702
   438
slouken@11702
   439
        /* convert tmp/ARGB8888 to dst/RGB */
slouken@11702
   440
        ret = SDL_ConvertPixels(width, height, SDL_PIXELFORMAT_ARGB8888, tmp, tmp_pitch, dst_format, dst, dst_pitch);
slouken@11702
   441
        SDL_free(tmp);
slouken@11702
   442
        return ret;
slouken@11702
   443
    }
slouken@11702
   444
slouken@11702
   445
    return SDL_SetError("Unsupported YUV conversion");
slouken@11702
   446
}
slouken@11702
   447
slouken@11702
   448
struct RGB2YUVFactors
slouken@11702
   449
{
slouken@11702
   450
    int y_offset;
slouken@11702
   451
    float y[3]; /* Rfactor, Gfactor, Bfactor */
slouken@11702
   452
    float u[3]; /* Rfactor, Gfactor, Bfactor */
slouken@11702
   453
    float v[3]; /* Rfactor, Gfactor, Bfactor */
slouken@11702
   454
};
slouken@11702
   455
slouken@11702
   456
static int
slouken@11702
   457
SDL_ConvertPixels_ARGB8888_to_YUV(int width, int height, const void *src, int src_pitch, Uint32 dst_format, void *dst, int dst_pitch)
slouken@11702
   458
{
slouken@11702
   459
    const int src_pitch_x_2    = src_pitch * 2;
slouken@11702
   460
    const int height_half      = height / 2;
slouken@11702
   461
    const int height_remainder = (height & 0x1);
slouken@11702
   462
    const int width_half       = width / 2;
slouken@11702
   463
    const int width_remainder  = (width & 0x1);
slouken@11702
   464
    int i, j;
slouken@11702
   465
 
slouken@11702
   466
    static struct RGB2YUVFactors RGB2YUVFactorTables[SDL_YUV_CONVERSION_BT709 + 1] =
slouken@11702
   467
    {
slouken@11702
   468
        /* ITU-T T.871 (JPEG) */
slouken@11702
   469
        {
slouken@11702
   470
            0,
slouken@11702
   471
            {  0.2990f,  0.5870f,  0.1140f },
slouken@11702
   472
            { -0.1687f, -0.3313f,  0.5000f },
slouken@11702
   473
            {  0.5000f, -0.4187f, -0.0813f },
slouken@11702
   474
        },
slouken@11702
   475
        /* ITU-R BT.601-7 */
slouken@11702
   476
        {
slouken@11702
   477
            16,
slouken@11702
   478
            {  0.2568f,  0.5041f,  0.0979f },
slouken@11702
   479
            { -0.1482f, -0.2910f,  0.4392f },
slouken@11702
   480
            {  0.4392f, -0.3678f, -0.0714f },
slouken@11702
   481
        },
slouken@11702
   482
        /* ITU-R BT.709-6 */
slouken@11702
   483
        {
slouken@11702
   484
            16,
slouken@11702
   485
            { 0.1826f,  0.6142f,  0.0620f },
slouken@11702
   486
            {-0.1006f, -0.3386f,  0.4392f },
slouken@11702
   487
            { 0.4392f, -0.3989f, -0.0403f },
slouken@11702
   488
        },
slouken@11702
   489
    };
slouken@11702
   490
    const struct RGB2YUVFactors *cvt = &RGB2YUVFactorTables[SDL_GetYUVConversionModeForResolution(width, height)];
slouken@11702
   491
slouken@11702
   492
#define MAKE_Y(r, g, b) (Uint8)((int)(cvt->y[0] * (r) + cvt->y[1] * (g) + cvt->y[2] * (b) + 0.5f) + cvt->y_offset)
slouken@11702
   493
#define MAKE_U(r, g, b) (Uint8)((int)(cvt->u[0] * (r) + cvt->u[1] * (g) + cvt->u[2] * (b) + 0.5f) + 128)
slouken@11702
   494
#define MAKE_V(r, g, b) (Uint8)((int)(cvt->v[0] * (r) + cvt->v[1] * (g) + cvt->v[2] * (b) + 0.5f) + 128)
slouken@11702
   495
slouken@11702
   496
#define READ_2x2_PIXELS                                                                                         \
slouken@11702
   497
        const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i];                                                    \
slouken@11702
   498
        const Uint32 p2 = ((const Uint32 *)curr_row)[2 * i + 1];                                                \
slouken@11702
   499
        const Uint32 p3 = ((const Uint32 *)next_row)[2 * i];                                                    \
slouken@11702
   500
        const Uint32 p4 = ((const Uint32 *)next_row)[2 * i + 1];                                                \
slouken@11702
   501
        const Uint32 r = ((p1 & 0x00ff0000) + (p2 & 0x00ff0000) + (p3 & 0x00ff0000) + (p4 & 0x00ff0000)) >> 18; \
slouken@11702
   502
        const Uint32 g = ((p1 & 0x0000ff00) + (p2 & 0x0000ff00) + (p3 & 0x0000ff00) + (p4 & 0x0000ff00)) >> 10; \
slouken@11702
   503
        const Uint32 b = ((p1 & 0x000000ff) + (p2 & 0x000000ff) + (p3 & 0x000000ff) + (p4 & 0x000000ff)) >> 2;  \
slouken@11702
   504
slouken@11702
   505
#define READ_2x1_PIXELS                                                                                         \
slouken@11702
   506
        const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i];                                                    \
slouken@11702
   507
        const Uint32 p2 = ((const Uint32 *)next_row)[2 * i];                                                    \
slouken@11702
   508
        const Uint32 r = ((p1 & 0x00ff0000) + (p2 & 0x00ff0000)) >> 17;                                         \
slouken@11702
   509
        const Uint32 g = ((p1 & 0x0000ff00) + (p2 & 0x0000ff00)) >> 9;                                          \
slouken@11702
   510
        const Uint32 b = ((p1 & 0x000000ff) + (p2 & 0x000000ff)) >> 1;                                          \
slouken@11702
   511
slouken@11702
   512
#define READ_1x2_PIXELS                                                                                         \
slouken@11702
   513
        const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i];                                                    \
slouken@11702
   514
        const Uint32 p2 = ((const Uint32 *)curr_row)[2 * i + 1];                                                \
slouken@11702
   515
        const Uint32 r = ((p1 & 0x00ff0000) + (p2 & 0x00ff0000)) >> 17;                                         \
slouken@11702
   516
        const Uint32 g = ((p1 & 0x0000ff00) + (p2 & 0x0000ff00)) >> 9;                                          \
slouken@11702
   517
        const Uint32 b = ((p1 & 0x000000ff) + (p2 & 0x000000ff)) >> 1;                                          \
slouken@11702
   518
slouken@11702
   519
#define READ_1x1_PIXEL                                                                                          \
slouken@11702
   520
        const Uint32 p = ((const Uint32 *)curr_row)[2 * i];                                                     \
slouken@11702
   521
        const Uint32 r = (p & 0x00ff0000) >> 16;                                                                \
slouken@11702
   522
        const Uint32 g = (p & 0x0000ff00) >> 8;                                                                 \
slouken@11702
   523
        const Uint32 b = (p & 0x000000ff);                                                                      \
slouken@11702
   524
slouken@11702
   525
#define READ_TWO_RGB_PIXELS                                                                                     \
slouken@11702
   526
        const Uint32 p = ((const Uint32 *)curr_row)[2 * i];                                                     \
slouken@11702
   527
        const Uint32 r = (p & 0x00ff0000) >> 16;                                                                \
slouken@11702
   528
        const Uint32 g = (p & 0x0000ff00) >> 8;                                                                 \
slouken@11702
   529
        const Uint32 b = (p & 0x000000ff);                                                                      \
slouken@11702
   530
        const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i + 1];                                                \
slouken@11702
   531
        const Uint32 r1 = (p1 & 0x00ff0000) >> 16;                                                              \
slouken@11702
   532
        const Uint32 g1 = (p1 & 0x0000ff00) >> 8;                                                               \
slouken@11702
   533
        const Uint32 b1 = (p1 & 0x000000ff);                                                                    \
slouken@11702
   534
        const Uint32 R = (r + r1)/2;                                                                            \
slouken@11702
   535
        const Uint32 G = (g + g1)/2;                                                                            \
slouken@11702
   536
        const Uint32 B = (b + b1)/2;                                                                            \
slouken@11702
   537
slouken@11702
   538
#define READ_ONE_RGB_PIXEL  READ_1x1_PIXEL
slouken@11702
   539
slouken@11702
   540
    switch (dst_format) 
slouken@11702
   541
    {
slouken@11702
   542
    case SDL_PIXELFORMAT_YV12:
slouken@11702
   543
    case SDL_PIXELFORMAT_IYUV:
slouken@11702
   544
    case SDL_PIXELFORMAT_NV12:
slouken@11702
   545
    case SDL_PIXELFORMAT_NV21:
slouken@11702
   546
        {
slouken@11702
   547
            const Uint8 *curr_row, *next_row;
slouken@11702
   548
            
slouken@11702
   549
            Uint8 *plane_y;
slouken@11702
   550
            Uint8 *plane_u;
slouken@11702
   551
            Uint8 *plane_v;
slouken@11702
   552
            Uint8 *plane_interleaved_uv;
slouken@11702
   553
            Uint32 y_stride, uv_stride, y_skip, uv_skip;
slouken@11702
   554
slouken@11702
   555
            GetYUVPlanes(width, height, dst_format, dst, dst_pitch,
slouken@12201
   556
                         (const Uint8 **)&plane_y, (const Uint8 **)&plane_u, (const Uint8 **)&plane_v,
slouken@11702
   557
                         &y_stride, &uv_stride);
slouken@11702
   558
            plane_interleaved_uv = (plane_y + height * y_stride);
slouken@11702
   559
            y_skip = (y_stride - width);
slouken@11702
   560
slouken@11702
   561
            curr_row = (const Uint8*)src;
slouken@11702
   562
slouken@11702
   563
            /* Write Y plane */
slouken@11702
   564
            for (j = 0; j < height; j++) {
slouken@11702
   565
                for (i = 0; i < width; i++) {
slouken@11702
   566
                    const Uint32 p1 = ((const Uint32 *)curr_row)[i];
slouken@11702
   567
                    const Uint32 r = (p1 & 0x00ff0000) >> 16;
slouken@11702
   568
                    const Uint32 g = (p1 & 0x0000ff00) >> 8;
slouken@11702
   569
                    const Uint32 b = (p1 & 0x000000ff);
slouken@11702
   570
                    *plane_y++ = MAKE_Y(r, g, b);
slouken@11702
   571
                }
slouken@11702
   572
                plane_y += y_skip;
slouken@11702
   573
                curr_row += src_pitch;
slouken@11702
   574
            }
slouken@11702
   575
slouken@11702
   576
            curr_row = (const Uint8*)src;
slouken@11702
   577
            next_row = (const Uint8*)src;
slouken@11702
   578
            next_row += src_pitch;
slouken@11702
   579
slouken@11702
   580
            if (dst_format == SDL_PIXELFORMAT_YV12 || dst_format == SDL_PIXELFORMAT_IYUV)
slouken@11702
   581
            {
slouken@11702
   582
                /* Write UV planes, not interleaved */
slouken@11702
   583
                uv_skip = (uv_stride - (width + 1)/2);
slouken@11702
   584
                for (j = 0; j < height_half; j++) {
slouken@11702
   585
                    for (i = 0; i < width_half; i++) {
slouken@11702
   586
                        READ_2x2_PIXELS;
slouken@11702
   587
                        *plane_u++ = MAKE_U(r, g, b);
slouken@11702
   588
                        *plane_v++ = MAKE_V(r, g, b);
slouken@11702
   589
                    }
slouken@11702
   590
                    if (width_remainder) {
slouken@11702
   591
                        READ_2x1_PIXELS;
slouken@11702
   592
                        *plane_u++ = MAKE_U(r, g, b);
slouken@11702
   593
                        *plane_v++ = MAKE_V(r, g, b);
slouken@11702
   594
                    }
slouken@11702
   595
                    plane_u += uv_skip;
slouken@11702
   596
                    plane_v += uv_skip;
slouken@11702
   597
                    curr_row += src_pitch_x_2;
slouken@11702
   598
                    next_row += src_pitch_x_2;
slouken@11702
   599
                }
slouken@11702
   600
                if (height_remainder) {
slouken@11702
   601
                    for (i = 0; i < width_half; i++) {
slouken@11702
   602
                        READ_1x2_PIXELS;
slouken@11702
   603
                        *plane_u++ = MAKE_U(r, g, b);
slouken@11702
   604
                        *plane_v++ = MAKE_V(r, g, b);
slouken@11702
   605
                    }
slouken@11702
   606
                    if (width_remainder) {
slouken@11702
   607
                        READ_1x1_PIXEL;
slouken@11702
   608
                        *plane_u++ = MAKE_U(r, g, b);
slouken@11702
   609
                        *plane_v++ = MAKE_V(r, g, b);
slouken@11702
   610
                    }
slouken@11702
   611
                    plane_u += uv_skip;
slouken@11702
   612
                    plane_v += uv_skip;
slouken@11702
   613
                }
slouken@11702
   614
            }
slouken@11702
   615
            else if (dst_format == SDL_PIXELFORMAT_NV12)
slouken@11702
   616
            {
slouken@11702
   617
                uv_skip = (uv_stride - ((width + 1)/2)*2);
slouken@11702
   618
                for (j = 0; j < height_half; j++) {
slouken@11702
   619
                    for (i = 0; i < width_half; i++) {
slouken@11702
   620
                        READ_2x2_PIXELS;
slouken@11702
   621
                        *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11702
   622
                        *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11702
   623
                    }
slouken@11702
   624
                    if (width_remainder) {
slouken@11702
   625
                        READ_2x1_PIXELS;
slouken@11702
   626
                        *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11702
   627
                        *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11702
   628
                    }
slouken@11702
   629
                    plane_interleaved_uv += uv_skip;
slouken@11702
   630
                    curr_row += src_pitch_x_2;
slouken@11702
   631
                    next_row += src_pitch_x_2;
slouken@11702
   632
                }
slouken@11702
   633
                if (height_remainder) {
slouken@11702
   634
                    for (i = 0; i < width_half; i++) {
slouken@11702
   635
                        READ_1x2_PIXELS;
slouken@11702
   636
                        *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11702
   637
                        *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11702
   638
                    }
slouken@11702
   639
                    if (width_remainder) {
slouken@11702
   640
                        READ_1x1_PIXEL;
slouken@11702
   641
                        *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11702
   642
                        *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11702
   643
                    }
slouken@11702
   644
                }
slouken@11702
   645
            } 
slouken@11702
   646
            else /* dst_format == SDL_PIXELFORMAT_NV21 */
slouken@11702
   647
            {
slouken@11702
   648
                uv_skip = (uv_stride - ((width + 1)/2)*2);
slouken@11702
   649
                for (j = 0; j < height_half; j++) {
slouken@11702
   650
                    for (i = 0; i < width_half; i++) {
slouken@11702
   651
                        READ_2x2_PIXELS;
slouken@11702
   652
                        *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11702
   653
                        *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11702
   654
                    }
slouken@11702
   655
                    if (width_remainder) {
slouken@11702
   656
                        READ_2x1_PIXELS;
slouken@11702
   657
                        *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11702
   658
                        *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11702
   659
                    }
slouken@11702
   660
                    plane_interleaved_uv += uv_skip;
slouken@11702
   661
                    curr_row += src_pitch_x_2;
slouken@11702
   662
                    next_row += src_pitch_x_2;
slouken@11702
   663
                }
slouken@11702
   664
                if (height_remainder) {
slouken@11702
   665
                    for (i = 0; i < width_half; i++) {
slouken@11702
   666
                        READ_1x2_PIXELS;
slouken@11702
   667
                        *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11702
   668
                        *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11702
   669
                    }
slouken@11702
   670
                    if (width_remainder) {
slouken@11702
   671
                        READ_1x1_PIXEL;
slouken@11702
   672
                        *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11702
   673
                        *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11702
   674
                    }
slouken@11702
   675
                }
slouken@11702
   676
            }
slouken@11702
   677
        }
slouken@11702
   678
        break;
slouken@11702
   679
slouken@11702
   680
    case SDL_PIXELFORMAT_YUY2:
slouken@11702
   681
    case SDL_PIXELFORMAT_UYVY:
slouken@11702
   682
    case SDL_PIXELFORMAT_YVYU:
slouken@11702
   683
        {
slouken@11702
   684
            const Uint8 *curr_row = (const Uint8*) src;
slouken@11702
   685
            Uint8 *plane           = (Uint8*) dst;
slouken@11702
   686
            const int row_size = (4 * ((width + 1) / 2));
slouken@11702
   687
            int plane_skip;
slouken@11702
   688
slouken@11702
   689
            if (dst_pitch < row_size) {
slouken@11702
   690
                return SDL_SetError("Destination pitch is too small, expected at least %d\n", row_size);
slouken@11702
   691
            }
slouken@11702
   692
            plane_skip = (dst_pitch - row_size);
slouken@11702
   693
slouken@11702
   694
            /* Write YUV plane, packed */
slouken@11702
   695
            if (dst_format == SDL_PIXELFORMAT_YUY2) 
slouken@11702
   696
            {
slouken@11702
   697
                for (j = 0; j < height; j++) {
slouken@11702
   698
                    for (i = 0; i < width_half; i++) {
slouken@11702
   699
                        READ_TWO_RGB_PIXELS;
slouken@11702
   700
                        /* Y U Y1 V */
slouken@11702
   701
                        *plane++ = MAKE_Y(r, g, b);
slouken@11702
   702
                        *plane++ = MAKE_U(R, G, B);
slouken@11702
   703
                        *plane++ = MAKE_Y(r1, g1, b1);
slouken@11702
   704
                        *plane++ = MAKE_V(R, G, B);
slouken@11702
   705
                    }
slouken@11702
   706
                    if (width_remainder) {
slouken@11702
   707
                        READ_ONE_RGB_PIXEL;
slouken@11702
   708
                        /* Y U Y V */
slouken@11702
   709
                        *plane++ = MAKE_Y(r, g, b);
slouken@11702
   710
                        *plane++ = MAKE_U(r, g, b);
slouken@11702
   711
                        *plane++ = MAKE_Y(r, g, b);
slouken@11702
   712
                        *plane++ = MAKE_V(r, g, b);
slouken@11702
   713
                    }
slouken@11702
   714
                    plane += plane_skip;
slouken@11702
   715
                    curr_row += src_pitch;
slouken@11702
   716
                }
slouken@11702
   717
            } 
slouken@11702
   718
            else if (dst_format == SDL_PIXELFORMAT_UYVY)
slouken@11702
   719
            {
slouken@11702
   720
                for (j = 0; j < height; j++) {
slouken@11702
   721
                    for (i = 0; i < width_half; i++) {
slouken@11702
   722
                        READ_TWO_RGB_PIXELS;
slouken@11702
   723
                        /* U Y V Y1 */
slouken@11702
   724
                        *plane++ = MAKE_U(R, G, B);
slouken@11702
   725
                        *plane++ = MAKE_Y(r, g, b);
slouken@11702
   726
                        *plane++ = MAKE_V(R, G, B);
slouken@11702
   727
                        *plane++ = MAKE_Y(r1, g1, b1);
slouken@11702
   728
                    }
slouken@11702
   729
                    if (width_remainder) {
slouken@11702
   730
                        READ_ONE_RGB_PIXEL;
slouken@11702
   731
                        /* U Y V Y */
slouken@11702
   732
                        *plane++ = MAKE_U(r, g, b);
slouken@11702
   733
                        *plane++ = MAKE_Y(r, g, b);
slouken@11702
   734
                        *plane++ = MAKE_V(r, g, b);
slouken@11702
   735
                        *plane++ = MAKE_Y(r, g, b);
slouken@11702
   736
                    }
slouken@11702
   737
                    plane += plane_skip;
slouken@11702
   738
                    curr_row += src_pitch;
slouken@11702
   739
                }
slouken@11702
   740
            }
slouken@11702
   741
            else if (dst_format == SDL_PIXELFORMAT_YVYU)
slouken@11702
   742
            {
slouken@11702
   743
                for (j = 0; j < height; j++) {
slouken@11702
   744
                    for (i = 0; i < width_half; i++) {
slouken@11702
   745
                        READ_TWO_RGB_PIXELS;
slouken@11702
   746
                        /* Y V Y1 U */
slouken@11702
   747
                        *plane++ = MAKE_Y(r, g, b);
slouken@11702
   748
                        *plane++ = MAKE_V(R, G, B);
slouken@11702
   749
                        *plane++ = MAKE_Y(r1, g1, b1);
slouken@11702
   750
                        *plane++ = MAKE_U(R, G, B);
slouken@11702
   751
                    }
slouken@11702
   752
                    if (width_remainder) {
slouken@11702
   753
                        READ_ONE_RGB_PIXEL;
slouken@11702
   754
                        /* Y V Y U */
slouken@11702
   755
                        *plane++ = MAKE_Y(r, g, b);
slouken@11702
   756
                        *plane++ = MAKE_V(r, g, b);
slouken@11702
   757
                        *plane++ = MAKE_Y(r, g, b);
slouken@11702
   758
                        *plane++ = MAKE_U(r, g, b);
slouken@11702
   759
                    }
slouken@11702
   760
                    plane += plane_skip;
slouken@11702
   761
                    curr_row += src_pitch;
slouken@11702
   762
                }
slouken@11702
   763
            }
slouken@11702
   764
        }
slouken@11702
   765
        break;
slouken@11702
   766
slouken@11702
   767
    default:
slouken@11702
   768
        return SDL_SetError("Unsupported YUV destination format: %s", SDL_GetPixelFormatName(dst_format));
slouken@11702
   769
    }
slouken@11702
   770
#undef MAKE_Y
slouken@11702
   771
#undef MAKE_U
slouken@11702
   772
#undef MAKE_V
slouken@11702
   773
#undef READ_2x2_PIXELS
slouken@11702
   774
#undef READ_2x1_PIXELS
slouken@11702
   775
#undef READ_1x2_PIXELS
slouken@11702
   776
#undef READ_1x1_PIXEL
slouken@11702
   777
#undef READ_TWO_RGB_PIXELS
slouken@11702
   778
#undef READ_ONE_RGB_PIXEL
slouken@11702
   779
    return 0;
slouken@11702
   780
}
slouken@11702
   781
slouken@11702
   782
int
slouken@11702
   783
SDL_ConvertPixels_RGB_to_YUV(int width, int height,
slouken@11702
   784
         Uint32 src_format, const void *src, int src_pitch,
slouken@11702
   785
         Uint32 dst_format, void *dst, int dst_pitch)
slouken@11702
   786
{
slouken@11702
   787
#if 0 /* Doesn't handle odd widths */
slouken@11702
   788
    /* RGB24 to FOURCC */
slouken@11702
   789
    if (src_format == SDL_PIXELFORMAT_RGB24) {
slouken@11702
   790
        Uint8 *y;
slouken@11702
   791
        Uint8 *u;
slouken@11702
   792
        Uint8 *v;
slouken@11702
   793
        Uint32 y_stride;
slouken@11702
   794
        Uint32 uv_stride;
slouken@11702
   795
        YCbCrType yuv_type;
slouken@11702
   796
slouken@11702
   797
        if (GetYUVPlanes(width, height, dst_format, dst, dst_pitch, (const Uint8 **)&y, (const Uint8 **)&u, (const Uint8 **)&v, &y_stride, &uv_stride) < 0) {
slouken@11702
   798
            return -1;
slouken@11702
   799
        }
slouken@11702
   800
slouken@11702
   801
        if (GetYUVConversionType(width, height, &yuv_type) < 0) {
slouken@11702
   802
            return -1;
slouken@11702
   803
        }
slouken@11702
   804
slouken@11702
   805
        rgb24_yuv420_std(width, height, src, src_pitch, y, u, v, y_stride, uv_stride, yuv_type);
slouken@11702
   806
        return 0;
slouken@11702
   807
    }
slouken@11702
   808
#endif
slouken@11702
   809
slouken@11702
   810
    /* ARGB8888 to FOURCC */
slouken@11702
   811
    if (src_format == SDL_PIXELFORMAT_ARGB8888) {
slouken@11702
   812
        return SDL_ConvertPixels_ARGB8888_to_YUV(width, height, src, src_pitch, dst_format, dst, dst_pitch);
slouken@11702
   813
    }
slouken@11702
   814
slouken@11702
   815
    /* not ARGB8888 to FOURCC : need an intermediate conversion */
slouken@11702
   816
    {
slouken@11702
   817
        int ret;
slouken@11702
   818
        void *tmp;
slouken@11702
   819
        int tmp_pitch = (width * sizeof(Uint32));
slouken@11702
   820
slouken@11702
   821
        tmp = SDL_malloc(tmp_pitch * height);
slouken@11702
   822
        if (tmp == NULL) {
slouken@11702
   823
            return SDL_OutOfMemory();
slouken@11702
   824
        }
slouken@11702
   825
slouken@11702
   826
        /* convert src/src_format to tmp/ARGB8888 */
slouken@11702
   827
        ret = SDL_ConvertPixels(width, height, src_format, src, src_pitch, SDL_PIXELFORMAT_ARGB8888, tmp, tmp_pitch);
slouken@11702
   828
        if (ret == -1) {
slouken@11702
   829
            SDL_free(tmp);
slouken@11702
   830
            return ret;
slouken@11702
   831
        }
slouken@11702
   832
slouken@11702
   833
        /* convert tmp/ARGB8888 to dst/FOURCC */
slouken@11702
   834
        ret = SDL_ConvertPixels_ARGB8888_to_YUV(width, height, tmp, tmp_pitch, dst_format, dst, dst_pitch);
slouken@11702
   835
        SDL_free(tmp);
slouken@11702
   836
        return ret;
slouken@11702
   837
    }
slouken@11702
   838
}
slouken@11702
   839
slouken@11702
   840
static int
slouken@11702
   841
SDL_ConvertPixels_YUV_to_YUV_Copy(int width, int height, Uint32 format,
slouken@11702
   842
        const void *src, int src_pitch, void *dst, int dst_pitch)
slouken@11702
   843
{
slouken@11702
   844
    int i;
slouken@11702
   845
slouken@11702
   846
    if (IsPlanar2x2Format(format)) {
slouken@11702
   847
        /* Y plane */
slouken@11702
   848
        for (i = height; i--;) {
slouken@11702
   849
            SDL_memcpy(dst, src, width);
slouken@11702
   850
            src = (const Uint8*)src + src_pitch;
slouken@11702
   851
            dst = (Uint8*)dst + dst_pitch;
slouken@11702
   852
        }
slouken@11702
   853
slouken@11702
   854
        if (format == SDL_PIXELFORMAT_YV12 || format == SDL_PIXELFORMAT_IYUV) {
slouken@11702
   855
            /* U and V planes are a quarter the size of the Y plane, rounded up */
slouken@11702
   856
            width = (width + 1) / 2;
slouken@11702
   857
            height = (height + 1) / 2;
slouken@11702
   858
            src_pitch = (src_pitch + 1) / 2;
slouken@11702
   859
            dst_pitch = (dst_pitch + 1) / 2;
slouken@11702
   860
            for (i = height * 2; i--;) {
slouken@11702
   861
                SDL_memcpy(dst, src, width);
slouken@11702
   862
                src = (const Uint8*)src + src_pitch;
slouken@11702
   863
                dst = (Uint8*)dst + dst_pitch;
slouken@11702
   864
            }
slouken@11702
   865
        } else if (format == SDL_PIXELFORMAT_NV12 || format == SDL_PIXELFORMAT_NV21) {
slouken@11702
   866
            /* U/V plane is half the height of the Y plane, rounded up */
slouken@11702
   867
            height = (height + 1) / 2;
slouken@11702
   868
            width = ((width + 1) / 2)*2;
slouken@11702
   869
            src_pitch = ((src_pitch + 1) / 2)*2;
slouken@11702
   870
            dst_pitch = ((dst_pitch + 1) / 2)*2;
slouken@11702
   871
            for (i = height; i--;) {
slouken@11702
   872
                SDL_memcpy(dst, src, width);
slouken@11702
   873
                src = (const Uint8*)src + src_pitch;
slouken@11702
   874
                dst = (Uint8*)dst + dst_pitch;
slouken@11702
   875
            }
slouken@11702
   876
        }
slouken@11702
   877
        return 0;
slouken@11702
   878
    }
slouken@11702
   879
slouken@11702
   880
    if (IsPacked4Format(format)) {
slouken@11702
   881
        /* Packed planes */
slouken@11702
   882
        width = 4 * ((width + 1) / 2);
slouken@11702
   883
        for (i = height; i--;) {
slouken@11702
   884
            SDL_memcpy(dst, src, width);
slouken@11702
   885
            src = (const Uint8*)src + src_pitch;
slouken@11702
   886
            dst = (Uint8*)dst + dst_pitch;
slouken@11702
   887
        }
slouken@11702
   888
        return 0;
slouken@11702
   889
    }
slouken@11702
   890
slouken@11702
   891
    return SDL_SetError("SDL_ConvertPixels_YUV_to_YUV_Copy: Unsupported YUV format: %s", SDL_GetPixelFormatName(format));
slouken@11702
   892
}
slouken@11702
   893
slouken@11702
   894
static int
slouken@11702
   895
SDL_ConvertPixels_SwapUVPlanes(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch)
slouken@11702
   896
{
slouken@11702
   897
    int y;
slouken@11702
   898
    const int UVwidth = (width + 1)/2;
slouken@11702
   899
    const int UVheight = (height + 1)/2;
slouken@11702
   900
slouken@11702
   901
    /* Skip the Y plane */
slouken@11702
   902
    src = (const Uint8 *)src + height * src_pitch;
slouken@11702
   903
    dst = (Uint8 *)dst + height * dst_pitch;
slouken@11702
   904
slouken@11702
   905
    if (src == dst) {
slouken@11702
   906
        int UVpitch = (dst_pitch + 1)/2;
slouken@11702
   907
        Uint8 *tmp;
slouken@11702
   908
        Uint8 *row1 = dst;
slouken@11702
   909
        Uint8 *row2 = (Uint8 *)dst + UVheight * UVpitch;
slouken@11702
   910
slouken@11702
   911
        /* Allocate a temporary row for the swap */
slouken@11702
   912
        tmp = (Uint8 *)SDL_malloc(UVwidth);
slouken@11702
   913
        if (!tmp) {
slouken@11702
   914
            return SDL_OutOfMemory();
slouken@11702
   915
        }
slouken@11702
   916
        for (y = 0; y < UVheight; ++y) {
slouken@11702
   917
            SDL_memcpy(tmp, row1, UVwidth);
slouken@11702
   918
            SDL_memcpy(row1, row2, UVwidth);
slouken@11702
   919
            SDL_memcpy(row2, tmp, UVwidth);
slouken@11702
   920
            row1 += UVpitch;
slouken@11702
   921
            row2 += UVpitch;
slouken@11702
   922
        }
slouken@11702
   923
        SDL_free(tmp);
slouken@11702
   924
    } else {
slouken@11702
   925
        const Uint8 *srcUV;
slouken@11702
   926
        Uint8 *dstUV;
slouken@11702
   927
        int srcUVPitch = ((src_pitch + 1)/2);
slouken@11702
   928
        int dstUVPitch = ((dst_pitch + 1)/2);
slouken@11702
   929
slouken@11702
   930
        /* Copy the first plane */
slouken@11702
   931
        srcUV = (const Uint8 *)src;
slouken@11702
   932
        dstUV = (Uint8 *)dst + UVheight * dstUVPitch;
slouken@11702
   933
        for (y = 0; y < UVheight; ++y) {
slouken@11702
   934
            SDL_memcpy(dstUV, srcUV, UVwidth);
slouken@11702
   935
            srcUV += srcUVPitch;
slouken@11702
   936
            dstUV += dstUVPitch;
slouken@11702
   937
        }
slouken@11702
   938
slouken@11702
   939
        /* Copy the second plane */
slouken@11702
   940
        dstUV = (Uint8 *)dst;
slouken@11702
   941
        for (y = 0; y < UVheight; ++y) {
slouken@11702
   942
            SDL_memcpy(dstUV, srcUV, UVwidth);
slouken@11702
   943
            srcUV += srcUVPitch;
slouken@11702
   944
            dstUV += dstUVPitch;
slouken@11702
   945
        }
slouken@11702
   946
    }
slouken@11702
   947
    return 0;
slouken@11702
   948
}
slouken@11702
   949
slouken@11702
   950
static int
slouken@11702
   951
SDL_ConvertPixels_PackUVPlanes_to_NV(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch, SDL_bool reverseUV)
slouken@11702
   952
{
slouken@11702
   953
    int x, y;
slouken@11702
   954
    const int UVwidth = (width + 1)/2;
slouken@11702
   955
    const int UVheight = (height + 1)/2;
slouken@11702
   956
    const int srcUVPitch = ((src_pitch + 1)/2);
slouken@11702
   957
    const int srcUVPitchLeft = srcUVPitch - UVwidth;
slouken@11702
   958
    const int dstUVPitch = ((dst_pitch + 1)/2)*2;
slouken@11702
   959
    const int dstUVPitchLeft = dstUVPitch - UVwidth*2;
slouken@11702
   960
    const Uint8 *src1, *src2;
slouken@11702
   961
    Uint8 *dstUV;
slouken@11702
   962
    Uint8 *tmp = NULL;
slouken@11702
   963
#ifdef __SSE2__
slouken@11702
   964
    const SDL_bool use_SSE2 = SDL_HasSSE2();
slouken@11702
   965
#endif
slouken@11702
   966
slouken@11702
   967
    /* Skip the Y plane */
slouken@11702
   968
    src = (const Uint8 *)src + height * src_pitch;
slouken@11702
   969
    dst = (Uint8 *)dst + height * dst_pitch;
slouken@11702
   970
slouken@11702
   971
    if (src == dst) {
slouken@11702
   972
        /* Need to make a copy of the buffer so we don't clobber it while converting */
slouken@11702
   973
        tmp = (Uint8 *)SDL_malloc(2*UVheight*srcUVPitch);
slouken@11702
   974
        if (!tmp) {
slouken@11702
   975
            return SDL_OutOfMemory();
slouken@11702
   976
        }
slouken@11702
   977
        SDL_memcpy(tmp, src, 2*UVheight*srcUVPitch);
slouken@11702
   978
        src = tmp;
slouken@11702
   979
    }
slouken@11702
   980
slouken@11702
   981
    if (reverseUV) {
slouken@11702
   982
        src2 = (const Uint8 *)src;
slouken@11702
   983
        src1 = src2 + UVheight * srcUVPitch;
slouken@11702
   984
    } else {
slouken@11702
   985
        src1 = (const Uint8 *)src;
slouken@11702
   986
        src2 = src1 + UVheight * srcUVPitch;
slouken@11702
   987
    }
slouken@11702
   988
    dstUV = (Uint8 *)dst;
slouken@11702
   989
slouken@11702
   990
    y = UVheight;
slouken@11702
   991
    while (y--) {
slouken@11702
   992
        x = UVwidth;
slouken@11702
   993
#ifdef __SSE2__
slouken@11702
   994
        if (use_SSE2) {
slouken@11702
   995
            while (x >= 16) {
slouken@11702
   996
                __m128i u = _mm_loadu_si128((__m128i *)src1);
slouken@11702
   997
                __m128i v = _mm_loadu_si128((__m128i *)src2);
slouken@11702
   998
                __m128i uv1 = _mm_unpacklo_epi8(u, v);
slouken@11702
   999
                __m128i uv2 = _mm_unpackhi_epi8(u, v);
slouken@11702
  1000
                _mm_storeu_si128((__m128i*)dstUV, uv1);
slouken@11702
  1001
                _mm_storeu_si128((__m128i*)(dstUV + 16), uv2);
slouken@11702
  1002
                src1 += 16;
slouken@11702
  1003
                src2 += 16;
slouken@11702
  1004
                dstUV += 32;
slouken@11702
  1005
                x -= 16;
slouken@11702
  1006
            }
slouken@11702
  1007
        }
slouken@11702
  1008
#endif
slouken@11702
  1009
        while (x--) {
slouken@11702
  1010
            *dstUV++ = *src1++;
slouken@11702
  1011
            *dstUV++ = *src2++;
slouken@11702
  1012
        }
slouken@11702
  1013
        src1 += srcUVPitchLeft;
slouken@11702
  1014
        src2 += srcUVPitchLeft;
slouken@11702
  1015
        dstUV += dstUVPitchLeft;
slouken@11702
  1016
    }
slouken@11702
  1017
slouken@11702
  1018
    if (tmp) {
slouken@11702
  1019
        SDL_free(tmp);
slouken@11702
  1020
    }
slouken@11702
  1021
    return 0;
slouken@11702
  1022
}
slouken@11702
  1023
slouken@11702
  1024
static int
slouken@11702
  1025
SDL_ConvertPixels_SplitNV_to_UVPlanes(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch, SDL_bool reverseUV)
slouken@11702
  1026
{
slouken@11702
  1027
    int x, y;
slouken@11702
  1028
    const int UVwidth = (width + 1)/2;
slouken@11702
  1029
    const int UVheight = (height + 1)/2;
slouken@11702
  1030
    const int srcUVPitch = ((src_pitch + 1)/2)*2;
slouken@11702
  1031
    const int srcUVPitchLeft = srcUVPitch - UVwidth*2;
slouken@11702
  1032
    const int dstUVPitch = ((dst_pitch + 1)/2);
slouken@11702
  1033
    const int dstUVPitchLeft = dstUVPitch - UVwidth;
slouken@11702
  1034
    const Uint8 *srcUV;
slouken@11702
  1035
    Uint8 *dst1, *dst2;
slouken@11702
  1036
    Uint8 *tmp = NULL;
slouken@11702
  1037
#ifdef __SSE2__
slouken@11702
  1038
    const SDL_bool use_SSE2 = SDL_HasSSE2();
slouken@11702
  1039
#endif
slouken@11702
  1040
slouken@11702
  1041
    /* Skip the Y plane */
slouken@11702
  1042
    src = (const Uint8 *)src + height * src_pitch;
slouken@11702
  1043
    dst = (Uint8 *)dst + height * dst_pitch;
slouken@11702
  1044
slouken@11702
  1045
    if (src == dst) {
slouken@11702
  1046
        /* Need to make a copy of the buffer so we don't clobber it while converting */
slouken@11702
  1047
        tmp = (Uint8 *)SDL_malloc(UVheight*srcUVPitch);
slouken@11702
  1048
        if (!tmp) {
slouken@11702
  1049
            return SDL_OutOfMemory();
slouken@11702
  1050
        }
slouken@11702
  1051
        SDL_memcpy(tmp, src, UVheight*srcUVPitch);
slouken@11702
  1052
        src = tmp;
slouken@11702
  1053
    }
slouken@11702
  1054
slouken@11702
  1055
    if (reverseUV) {
slouken@11702
  1056
        dst2 = (Uint8 *)dst;
slouken@11702
  1057
        dst1 = dst2 + UVheight * dstUVPitch;
slouken@11702
  1058
    } else {
slouken@11702
  1059
        dst1 = (Uint8 *)dst;
slouken@11702
  1060
        dst2 = dst1 + UVheight * dstUVPitch;
slouken@11702
  1061
    }
slouken@11702
  1062
    srcUV = (const Uint8 *)src;
slouken@11702
  1063
slouken@11702
  1064
    y = UVheight;
slouken@11702
  1065
    while (y--) {
slouken@11702
  1066
        x = UVwidth;
slouken@11702
  1067
#ifdef __SSE2__
slouken@11702
  1068
        if (use_SSE2) {
slouken@11702
  1069
            __m128i mask = _mm_set1_epi16(0x00FF);
slouken@11702
  1070
            while (x >= 16) {
slouken@11702
  1071
                __m128i uv1 = _mm_loadu_si128((__m128i*)srcUV);
slouken@11702
  1072
                __m128i uv2 = _mm_loadu_si128((__m128i*)(srcUV+16));
slouken@11702
  1073
                __m128i u1 = _mm_and_si128(uv1, mask);
slouken@11702
  1074
                __m128i u2 = _mm_and_si128(uv2, mask);
slouken@11702
  1075
                __m128i u = _mm_packus_epi16(u1, u2);
slouken@11702
  1076
                __m128i v1 = _mm_srli_epi16(uv1, 8);
slouken@11702
  1077
                __m128i v2 = _mm_srli_epi16(uv2, 8);
slouken@11702
  1078
                __m128i v = _mm_packus_epi16(v1, v2);
slouken@11702
  1079
                _mm_storeu_si128((__m128i*)dst1, u);
slouken@11702
  1080
                _mm_storeu_si128((__m128i*)dst2, v);
slouken@11702
  1081
                srcUV += 32;
slouken@11702
  1082
                dst1 += 16;
slouken@11702
  1083
                dst2 += 16;
slouken@11702
  1084
                x -= 16;
slouken@11702
  1085
            }
slouken@11702
  1086
        }
slouken@11702
  1087
#endif
slouken@11702
  1088
        while (x--) {
slouken@11702
  1089
            *dst1++ = *srcUV++;
slouken@11702
  1090
            *dst2++ = *srcUV++;
slouken@11702
  1091
        }
slouken@11702
  1092
        srcUV += srcUVPitchLeft;
slouken@11702
  1093
        dst1 += dstUVPitchLeft;
slouken@11702
  1094
        dst2 += dstUVPitchLeft;
slouken@11702
  1095
    }
slouken@11702
  1096
slouken@11702
  1097
    if (tmp) {
slouken@11702
  1098
        SDL_free(tmp);
slouken@11702
  1099
    }
slouken@11702
  1100
    return 0;
slouken@11702
  1101
}
slouken@11702
  1102
slouken@11702
  1103
static int
slouken@11702
  1104
SDL_ConvertPixels_SwapNV(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch)
slouken@11702
  1105
{
slouken@11702
  1106
    int x, y;
slouken@11702
  1107
    const int UVwidth = (width + 1)/2;
slouken@11702
  1108
    const int UVheight = (height + 1)/2;
slouken@11702
  1109
    const int srcUVPitch = ((src_pitch + 1)/2)*2;
slouken@11702
  1110
    const int srcUVPitchLeft = (srcUVPitch - UVwidth*2)/sizeof(Uint16);
slouken@11702
  1111
    const int dstUVPitch = ((dst_pitch + 1)/2)*2;
slouken@11702
  1112
    const int dstUVPitchLeft = (dstUVPitch - UVwidth*2)/sizeof(Uint16);
slouken@11702
  1113
    const Uint16 *srcUV;
slouken@11702
  1114
    Uint16 *dstUV;
slouken@11702
  1115
#ifdef __SSE2__
slouken@11702
  1116
    const SDL_bool use_SSE2 = SDL_HasSSE2();
slouken@11702
  1117
#endif
slouken@11702
  1118
slouken@11702
  1119
    /* Skip the Y plane */
slouken@11702
  1120
    src = (const Uint8 *)src + height * src_pitch;
slouken@11702
  1121
    dst = (Uint8 *)dst + height * dst_pitch;
slouken@11702
  1122
slouken@11702
  1123
    srcUV = (const Uint16 *)src;
slouken@11702
  1124
    dstUV = (Uint16 *)dst;
slouken@11702
  1125
    y = UVheight;
slouken@11702
  1126
    while (y--) {
slouken@11702
  1127
        x = UVwidth;
slouken@11702
  1128
#ifdef __SSE2__
slouken@11702
  1129
        if (use_SSE2) {
slouken@11702
  1130
            while (x >= 8) {
slouken@11702
  1131
                __m128i uv = _mm_loadu_si128((__m128i*)srcUV);
slouken@11702
  1132
                __m128i v = _mm_slli_epi16(uv, 8);
slouken@11702
  1133
                __m128i u = _mm_srli_epi16(uv, 8);
slouken@11702
  1134
                __m128i vu = _mm_or_si128(v, u);
slouken@11702
  1135
                _mm_storeu_si128((__m128i*)dstUV, vu);
slouken@11702
  1136
                srcUV += 8;
slouken@11702
  1137
                dstUV += 8;
slouken@11702
  1138
                x -= 8;
slouken@11702
  1139
            }
slouken@11702
  1140
        }
slouken@11702
  1141
#endif
slouken@11702
  1142
        while (x--) {
slouken@11702
  1143
            *dstUV++ = SDL_Swap16(*srcUV++);
slouken@11702
  1144
        }
slouken@11702
  1145
        srcUV += srcUVPitchLeft;
slouken@11702
  1146
        dstUV += dstUVPitchLeft;
slouken@11702
  1147
    }
slouken@11702
  1148
    return 0;
slouken@11702
  1149
}
slouken@11702
  1150
slouken@11702
  1151
static int
slouken@11702
  1152
SDL_ConvertPixels_Planar2x2_to_Planar2x2(int width, int height,
slouken@11702
  1153
         Uint32 src_format, const void *src, int src_pitch,
slouken@11702
  1154
         Uint32 dst_format, void *dst, int dst_pitch)
slouken@11702
  1155
{
slouken@11702
  1156
    if (src != dst) {
slouken@11702
  1157
        /* Copy Y plane */
slouken@11702
  1158
        int i;
slouken@11702
  1159
        const Uint8 *srcY = (const Uint8 *)src;
slouken@11702
  1160
        Uint8 *dstY = (Uint8 *)dst;
slouken@11702
  1161
        for (i = height; i--; ) {
slouken@11702
  1162
            SDL_memcpy(dstY, srcY, width);
slouken@11702
  1163
            srcY += src_pitch;
slouken@11702
  1164
            dstY += dst_pitch;
slouken@11702
  1165
        }
slouken@11702
  1166
    }
slouken@11702
  1167
slouken@11702
  1168
    switch (src_format) {
slouken@11702
  1169
    case SDL_PIXELFORMAT_YV12:
slouken@11702
  1170
        switch (dst_format) {
slouken@11702
  1171
        case SDL_PIXELFORMAT_IYUV:
slouken@11702
  1172
            return SDL_ConvertPixels_SwapUVPlanes(width, height, src, src_pitch, dst, dst_pitch);
slouken@11702
  1173
        case SDL_PIXELFORMAT_NV12:
slouken@11702
  1174
            return SDL_ConvertPixels_PackUVPlanes_to_NV(width, height, src, src_pitch, dst, dst_pitch, SDL_TRUE);
slouken@11702
  1175
        case SDL_PIXELFORMAT_NV21:
slouken@11702
  1176
            return SDL_ConvertPixels_PackUVPlanes_to_NV(width, height, src, src_pitch, dst, dst_pitch, SDL_FALSE);
slouken@11702
  1177
        default:
slouken@11702
  1178
            break;
slouken@11702
  1179
        }
slouken@11702
  1180
        break;
slouken@11702
  1181
    case SDL_PIXELFORMAT_IYUV:
slouken@11702
  1182
        switch (dst_format) {
slouken@11702
  1183
        case SDL_PIXELFORMAT_YV12:
slouken@11702
  1184
            return SDL_ConvertPixels_SwapUVPlanes(width, height, src, src_pitch, dst, dst_pitch);
slouken@11702
  1185
        case SDL_PIXELFORMAT_NV12:
slouken@11702
  1186
            return SDL_ConvertPixels_PackUVPlanes_to_NV(width, height, src, src_pitch, dst, dst_pitch, SDL_FALSE);
slouken@11702
  1187
        case SDL_PIXELFORMAT_NV21:
slouken@11702
  1188
            return SDL_ConvertPixels_PackUVPlanes_to_NV(width, height, src, src_pitch, dst, dst_pitch, SDL_TRUE);
slouken@11702
  1189
        default:
slouken@11702
  1190
            break;
slouken@11702
  1191
        }
slouken@11702
  1192
        break;
slouken@11702
  1193
    case SDL_PIXELFORMAT_NV12:
slouken@11702
  1194
        switch (dst_format) {
slouken@11702
  1195
        case SDL_PIXELFORMAT_YV12:
slouken@11702
  1196
            return SDL_ConvertPixels_SplitNV_to_UVPlanes(width, height, src, src_pitch, dst, dst_pitch, SDL_TRUE);
slouken@11702
  1197
        case SDL_PIXELFORMAT_IYUV:
slouken@11702
  1198
            return SDL_ConvertPixels_SplitNV_to_UVPlanes(width, height, src, src_pitch, dst, dst_pitch, SDL_FALSE);
slouken@11702
  1199
        case SDL_PIXELFORMAT_NV21:
slouken@11702
  1200
            return SDL_ConvertPixels_SwapNV(width, height, src, src_pitch, dst, dst_pitch);
slouken@11702
  1201
        default:
slouken@11702
  1202
            break;
slouken@11702
  1203
        }
slouken@11702
  1204
        break;
slouken@11702
  1205
    case SDL_PIXELFORMAT_NV21:
slouken@11702
  1206
        switch (dst_format) {
slouken@11702
  1207
        case SDL_PIXELFORMAT_YV12:
slouken@11702
  1208
            return SDL_ConvertPixels_SplitNV_to_UVPlanes(width, height, src, src_pitch, dst, dst_pitch, SDL_FALSE);
slouken@11702
  1209
        case SDL_PIXELFORMAT_IYUV:
slouken@11702
  1210
            return SDL_ConvertPixels_SplitNV_to_UVPlanes(width, height, src, src_pitch, dst, dst_pitch, SDL_TRUE);
slouken@11702
  1211
        case SDL_PIXELFORMAT_NV12:
slouken@11702
  1212
            return SDL_ConvertPixels_SwapNV(width, height, src, src_pitch, dst, dst_pitch);
slouken@11702
  1213
        default:
slouken@11702
  1214
            break;
slouken@11702
  1215
        }
slouken@11702
  1216
        break;
slouken@11702
  1217
    default:
slouken@11702
  1218
        break;
slouken@11702
  1219
    }
slouken@11702
  1220
    return SDL_SetError("SDL_ConvertPixels_Planar2x2_to_Planar2x2: Unsupported YUV conversion: %s -> %s", SDL_GetPixelFormatName(src_format), SDL_GetPixelFormatName(dst_format));
slouken@11702
  1221
}
slouken@11702
  1222
slouken@11702
  1223
#define PACKED4_TO_PACKED4_ROW_SSE2(shuffle)                                                        \
slouken@11702
  1224
    while (x >= 4) {                                                                                \
slouken@11702
  1225
        __m128i yuv = _mm_loadu_si128((__m128i*)srcYUV);                                            \
slouken@11702
  1226
        __m128i lo = _mm_unpacklo_epi8(yuv, _mm_setzero_si128());                                   \
slouken@11702
  1227
        __m128i hi = _mm_unpackhi_epi8(yuv, _mm_setzero_si128());                                   \
slouken@11702
  1228
        lo = _mm_shufflelo_epi16(lo, shuffle);                                                      \
slouken@11702
  1229
        lo = _mm_shufflehi_epi16(lo, shuffle);                                                      \
slouken@11702
  1230
        hi = _mm_shufflelo_epi16(hi, shuffle);                                                      \
slouken@11702
  1231
        hi = _mm_shufflehi_epi16(hi, shuffle);                                                      \
slouken@11702
  1232
        yuv = _mm_packus_epi16(lo, hi);                                                             \
slouken@11702
  1233
        _mm_storeu_si128((__m128i*)dstYUV, yuv);                                                    \
slouken@11702
  1234
        srcYUV += 16;                                                                               \
slouken@11702
  1235
        dstYUV += 16;                                                                               \
slouken@11702
  1236
        x -= 4;                                                                                     \
slouken@11702
  1237
    }                                                                                               \
slouken@11702
  1238
slouken@11702
  1239
static int
slouken@11702
  1240
SDL_ConvertPixels_YUY2_to_UYVY(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch)
slouken@11702
  1241
{
slouken@11702
  1242
    int x, y;
slouken@11702
  1243
    const int YUVwidth = (width + 1)/2;
slouken@11702
  1244
    const int srcYUVPitchLeft = (src_pitch - YUVwidth*4);
slouken@11702
  1245
    const int dstYUVPitchLeft = (dst_pitch - YUVwidth*4);
slouken@11702
  1246
    const Uint8 *srcYUV = (const Uint8 *)src;
slouken@11702
  1247
    Uint8 *dstYUV = (Uint8 *)dst;
slouken@11702
  1248
#ifdef __SSE2__
slouken@11702
  1249
    const SDL_bool use_SSE2 = SDL_HasSSE2();
slouken@11702
  1250
#endif
slouken@11702
  1251
slouken@11702
  1252
    y = height;
slouken@11702
  1253
    while (y--) {
slouken@11702
  1254
        x = YUVwidth;
slouken@11702
  1255
#ifdef __SSE2__
slouken@11702
  1256
        if (use_SSE2) {
slouken@11702
  1257
            PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(2, 3, 0, 1));
slouken@11702
  1258
        }
slouken@11702
  1259
#endif
slouken@11702
  1260
        while (x--) {
slouken@11702
  1261
            Uint8 Y1, U, Y2, V;
slouken@11702
  1262
slouken@11702
  1263
            Y1 = srcYUV[0];
slouken@11702
  1264
            U = srcYUV[1];
slouken@11702
  1265
            Y2 = srcYUV[2];
slouken@11702
  1266
            V = srcYUV[3];
slouken@11702
  1267
            srcYUV += 4;
slouken@11702
  1268
slouken@11702
  1269
            dstYUV[0] = U;
slouken@11702
  1270
            dstYUV[1] = Y1;
slouken@11702
  1271
            dstYUV[2] = V;
slouken@11702
  1272
            dstYUV[3] = Y2;
slouken@11702
  1273
            dstYUV += 4;
slouken@11702
  1274
        }
slouken@11702
  1275
        srcYUV += srcYUVPitchLeft;
slouken@11702
  1276
        dstYUV += dstYUVPitchLeft;
slouken@11702
  1277
    }
slouken@11702
  1278
    return 0;
slouken@11702
  1279
}
slouken@11702
  1280
slouken@11702
  1281
static int
slouken@11702
  1282
SDL_ConvertPixels_YUY2_to_YVYU(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch)
slouken@11702
  1283
{
slouken@11702
  1284
    int x, y;
slouken@11702
  1285
    const int YUVwidth = (width + 1)/2;
slouken@11702
  1286
    const int srcYUVPitchLeft = (src_pitch - YUVwidth*4);
slouken@11702
  1287
    const int dstYUVPitchLeft = (dst_pitch - YUVwidth*4);
slouken@11702
  1288
    const Uint8 *srcYUV = (const Uint8 *)src;
slouken@11702
  1289
    Uint8 *dstYUV = (Uint8 *)dst;
slouken@11702
  1290
#ifdef __SSE2__
slouken@11702
  1291
    const SDL_bool use_SSE2 = SDL_HasSSE2();
slouken@11702
  1292
#endif
slouken@11702
  1293
slouken@11702
  1294
    y = height;
slouken@11702
  1295
    while (y--) {
slouken@11702
  1296
        x = YUVwidth;
slouken@11702
  1297
#ifdef __SSE2__
slouken@11702
  1298
        if (use_SSE2) {
slouken@11702
  1299
            PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(1, 2, 3, 0));
slouken@11702
  1300
        }
slouken@11702
  1301
#endif
slouken@11702
  1302
        while (x--) {
slouken@11702
  1303
            Uint8 Y1, U, Y2, V;
slouken@11702
  1304
slouken@11702
  1305
            Y1 = srcYUV[0];
slouken@11702
  1306
            U = srcYUV[1];
slouken@11702
  1307
            Y2 = srcYUV[2];
slouken@11702
  1308
            V = srcYUV[3];
slouken@11702
  1309
            srcYUV += 4;
slouken@11702
  1310
slouken@11702
  1311
            dstYUV[0] = Y1;
slouken@11702
  1312
            dstYUV[1] = V;
slouken@11702
  1313
            dstYUV[2] = Y2;
slouken@11702
  1314
            dstYUV[3] = U;
slouken@11702
  1315
            dstYUV += 4;
slouken@11702
  1316
        }
slouken@11702
  1317
        srcYUV += srcYUVPitchLeft;
slouken@11702
  1318
        dstYUV += dstYUVPitchLeft;
slouken@11702
  1319
    }
slouken@11702
  1320
    return 0;
slouken@11702
  1321
}
slouken@11702
  1322
slouken@11702
  1323
static int
slouken@11702
  1324
SDL_ConvertPixels_UYVY_to_YUY2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch)
slouken@11702
  1325
{
slouken@11702
  1326
    int x, y;
slouken@11702
  1327
    const int YUVwidth = (width + 1)/2;
slouken@11702
  1328
    const int srcYUVPitchLeft = (src_pitch - YUVwidth*4);
slouken@11702
  1329
    const int dstYUVPitchLeft = (dst_pitch - YUVwidth*4);
slouken@11702
  1330
    const Uint8 *srcYUV = (const Uint8 *)src;
slouken@11702
  1331
    Uint8 *dstYUV = (Uint8 *)dst;
slouken@11702
  1332
#ifdef __SSE2__
slouken@11702
  1333
    const SDL_bool use_SSE2 = SDL_HasSSE2();
slouken@11702
  1334
#endif
slouken@11702
  1335
slouken@11702
  1336
    y = height;
slouken@11702
  1337
    while (y--) {
slouken@11702
  1338
        x = YUVwidth;
slouken@11702
  1339
#ifdef __SSE2__
slouken@11702
  1340
        if (use_SSE2) {
slouken@11702
  1341
            PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(2, 3, 0, 1));
slouken@11702
  1342
        }
slouken@11702
  1343
#endif
slouken@11702
  1344
        while (x--) {
slouken@11702
  1345
            Uint8 Y1, U, Y2, V;
slouken@11702
  1346
slouken@11702
  1347
            U = srcYUV[0];
slouken@11702
  1348
            Y1 = srcYUV[1];
slouken@11702
  1349
            V = srcYUV[2];
slouken@11702
  1350
            Y2 = srcYUV[3];
slouken@11702
  1351
            srcYUV += 4;
slouken@11702
  1352
slouken@11702
  1353
            dstYUV[0] = Y1;
slouken@11702
  1354
            dstYUV[1] = U;
slouken@11702
  1355
            dstYUV[2] = Y2;
slouken@11702
  1356
            dstYUV[3] = V;
slouken@11702
  1357
            dstYUV += 4;
slouken@11702
  1358
        }
slouken@11702
  1359
        srcYUV += srcYUVPitchLeft;
slouken@11702
  1360
        dstYUV += dstYUVPitchLeft;
slouken@11702
  1361
    }
slouken@11702
  1362
    return 0;
slouken@11702
  1363
}
slouken@11702
  1364
slouken@11702
  1365
static int
slouken@11702
  1366
SDL_ConvertPixels_UYVY_to_YVYU(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch)
slouken@11702
  1367
{
slouken@11702
  1368
    int x, y;
slouken@11702
  1369
    const int YUVwidth = (width + 1)/2;
slouken@11702
  1370
    const int srcYUVPitchLeft = (src_pitch - YUVwidth*4);
slouken@11702
  1371
    const int dstYUVPitchLeft = (dst_pitch - YUVwidth*4);
slouken@11702
  1372
    const Uint8 *srcYUV = (const Uint8 *)src;
slouken@11702
  1373
    Uint8 *dstYUV = (Uint8 *)dst;
slouken@11702
  1374
#ifdef __SSE2__
slouken@11702
  1375
    const SDL_bool use_SSE2 = SDL_HasSSE2();
slouken@11702
  1376
#endif
slouken@11702
  1377
slouken@11702
  1378
    y = height;
slouken@11702
  1379
    while (y--) {
slouken@11702
  1380
        x = YUVwidth;
slouken@11702
  1381
#ifdef __SSE2__
slouken@11702
  1382
        if (use_SSE2) {
slouken@11702
  1383
            PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(0, 3, 2, 1));
slouken@11702
  1384
        }
slouken@11702
  1385
#endif
slouken@11702
  1386
        while (x--) {
slouken@11702
  1387
            Uint8 Y1, U, Y2, V;
slouken@11702
  1388
slouken@11702
  1389
            U = srcYUV[0];
slouken@11702
  1390
            Y1 = srcYUV[1];
slouken@11702
  1391
            V = srcYUV[2];
slouken@11702
  1392
            Y2 = srcYUV[3];
slouken@11702
  1393
            srcYUV += 4;
slouken@11702
  1394
slouken@11702
  1395
            dstYUV[0] = Y1;
slouken@11702
  1396
            dstYUV[1] = V;
slouken@11702
  1397
            dstYUV[2] = Y2;
slouken@11702
  1398
            dstYUV[3] = U;
slouken@11702
  1399
            dstYUV += 4;
slouken@11702
  1400
        }
slouken@11702
  1401
        srcYUV += srcYUVPitchLeft;
slouken@11702
  1402
        dstYUV += dstYUVPitchLeft;
slouken@11702
  1403
    }
slouken@11702
  1404
    return 0;
slouken@11702
  1405
}
slouken@11702
  1406
slouken@11702
  1407
static int
slouken@11702
  1408
SDL_ConvertPixels_YVYU_to_YUY2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch)
slouken@11702
  1409
{
slouken@11702
  1410
    int x, y;
slouken@11702
  1411
    const int YUVwidth = (width + 1)/2;
slouken@11702
  1412
    const int srcYUVPitchLeft = (src_pitch - YUVwidth*4);
slouken@11702
  1413
    const int dstYUVPitchLeft = (dst_pitch - YUVwidth*4);
slouken@11702
  1414
    const Uint8 *srcYUV = (const Uint8 *)src;
slouken@11702
  1415
    Uint8 *dstYUV = (Uint8 *)dst;
slouken@11702
  1416
#ifdef __SSE2__
slouken@11702
  1417
    const SDL_bool use_SSE2 = SDL_HasSSE2();
slouken@11702
  1418
#endif
slouken@11702
  1419
slouken@11702
  1420
    y = height;
slouken@11702
  1421
    while (y--) {
slouken@11702
  1422
        x = YUVwidth;
slouken@11702
  1423
#ifdef __SSE2__
slouken@11702
  1424
        if (use_SSE2) {
slouken@11702
  1425
            PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(1, 2, 3, 0));
slouken@11702
  1426
        }
slouken@11702
  1427
#endif
slouken@11702
  1428
        while (x--) {
slouken@11702
  1429
            Uint8 Y1, U, Y2, V;
slouken@11702
  1430
slouken@11702
  1431
            Y1 = srcYUV[0];
slouken@11702
  1432
            V = srcYUV[1];
slouken@11702
  1433
            Y2 = srcYUV[2];
slouken@11702
  1434
            U = srcYUV[3];
slouken@11702
  1435
            srcYUV += 4;
slouken@11702
  1436
slouken@11702
  1437
            dstYUV[0] = Y1;
slouken@11702
  1438
            dstYUV[1] = U;
slouken@11702
  1439
            dstYUV[2] = Y2;
slouken@11702
  1440
            dstYUV[3] = V;
slouken@11702
  1441
            dstYUV += 4;
slouken@11702
  1442
        }
slouken@11702
  1443
        srcYUV += srcYUVPitchLeft;
slouken@11702
  1444
        dstYUV += dstYUVPitchLeft;
slouken@11702
  1445
    }
slouken@11702
  1446
    return 0;
slouken@11702
  1447
}
slouken@11702
  1448
slouken@11702
  1449
static int
slouken@11702
  1450
SDL_ConvertPixels_YVYU_to_UYVY(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch)
slouken@11702
  1451
{
slouken@11702
  1452
    int x, y;
slouken@11702
  1453
    const int YUVwidth = (width + 1)/2;
slouken@11702
  1454
    const int srcYUVPitchLeft = (src_pitch - YUVwidth*4);
slouken@11702
  1455
    const int dstYUVPitchLeft = (dst_pitch - YUVwidth*4);
slouken@11702
  1456
    const Uint8 *srcYUV = (const Uint8 *)src;
slouken@11702
  1457
    Uint8 *dstYUV = (Uint8 *)dst;
slouken@11702
  1458
#ifdef __SSE2__
slouken@11702
  1459
    const SDL_bool use_SSE2 = SDL_HasSSE2();
slouken@11702
  1460
#endif
slouken@11702
  1461
slouken@11702
  1462
    y = height;
slouken@11702
  1463
    while (y--) {
slouken@11702
  1464
        x = YUVwidth;
slouken@11702
  1465
#ifdef __SSE2__
slouken@11702
  1466
        if (use_SSE2) {
slouken@11702
  1467
            PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(2, 1, 0, 3));
slouken@11702
  1468
        }
slouken@11702
  1469
#endif
slouken@11702
  1470
        while (x--) {
slouken@11702
  1471
            Uint8 Y1, U, Y2, V;
slouken@11702
  1472
slouken@11702
  1473
            Y1 = srcYUV[0];
slouken@11702
  1474
            V = srcYUV[1];
slouken@11702
  1475
            Y2 = srcYUV[2];
slouken@11702
  1476
            U = srcYUV[3];
slouken@11702
  1477
            srcYUV += 4;
slouken@11702
  1478
slouken@11702
  1479
            dstYUV[0] = U;
slouken@11702
  1480
            dstYUV[1] = Y1;
slouken@11702
  1481
            dstYUV[2] = V;
slouken@11702
  1482
            dstYUV[3] = Y2;
slouken@11702
  1483
            dstYUV += 4;
slouken@11702
  1484
        }
slouken@11702
  1485
        srcYUV += srcYUVPitchLeft;
slouken@11702
  1486
        dstYUV += dstYUVPitchLeft;
slouken@11702
  1487
    }
slouken@11702
  1488
    return 0;
slouken@11702
  1489
}
slouken@11702
  1490
slouken@11702
  1491
static int
slouken@11702
  1492
SDL_ConvertPixels_Packed4_to_Packed4(int width, int height,
slouken@11702
  1493
         Uint32 src_format, const void *src, int src_pitch,
slouken@11702
  1494
         Uint32 dst_format, void *dst, int dst_pitch)
slouken@11702
  1495
{
slouken@11702
  1496
    switch (src_format) {
slouken@11702
  1497
    case SDL_PIXELFORMAT_YUY2:
slouken@11702
  1498
        switch (dst_format) {
slouken@11702
  1499
        case SDL_PIXELFORMAT_UYVY:
slouken@11702
  1500
            return SDL_ConvertPixels_YUY2_to_UYVY(width, height, src, src_pitch, dst, dst_pitch);
slouken@11702
  1501
        case SDL_PIXELFORMAT_YVYU:
slouken@11702
  1502
            return SDL_ConvertPixels_YUY2_to_YVYU(width, height, src, src_pitch, dst, dst_pitch);
slouken@11702
  1503
        default:
slouken@11702
  1504
            break;
slouken@11702
  1505
        }
slouken@11702
  1506
        break;
slouken@11702
  1507
    case SDL_PIXELFORMAT_UYVY:
slouken@11702
  1508
        switch (dst_format) {
slouken@11702
  1509
        case SDL_PIXELFORMAT_YUY2:
slouken@11702
  1510
            return SDL_ConvertPixels_UYVY_to_YUY2(width, height, src, src_pitch, dst, dst_pitch);
slouken@11702
  1511
        case SDL_PIXELFORMAT_YVYU:
slouken@11702
  1512
            return SDL_ConvertPixels_UYVY_to_YVYU(width, height, src, src_pitch, dst, dst_pitch);
slouken@11702
  1513
        default:
slouken@11702
  1514
            break;
slouken@11702
  1515
        }
slouken@11702
  1516
        break;
slouken@11702
  1517
    case SDL_PIXELFORMAT_YVYU:
slouken@11702
  1518
        switch (dst_format) {
slouken@11702
  1519
        case SDL_PIXELFORMAT_YUY2:
slouken@11702
  1520
            return SDL_ConvertPixels_YVYU_to_YUY2(width, height, src, src_pitch, dst, dst_pitch);
slouken@11702
  1521
        case SDL_PIXELFORMAT_UYVY:
slouken@11702
  1522
            return SDL_ConvertPixels_YVYU_to_UYVY(width, height, src, src_pitch, dst, dst_pitch);
slouken@11702
  1523
        default:
slouken@11702
  1524
            break;
slouken@11702
  1525
        }
slouken@11702
  1526
        break;
slouken@11702
  1527
    default:
slouken@11702
  1528
        break;
slouken@11702
  1529
    }
slouken@11702
  1530
    return SDL_SetError("SDL_ConvertPixels_Packed4_to_Packed4: Unsupported YUV conversion: %s -> %s", SDL_GetPixelFormatName(src_format), SDL_GetPixelFormatName(dst_format));
slouken@11702
  1531
}
slouken@11702
  1532
slouken@11702
  1533
static int
slouken@11702
  1534
SDL_ConvertPixels_Planar2x2_to_Packed4(int width, int height,
slouken@11702
  1535
         Uint32 src_format, const void *src, int src_pitch,
slouken@11702
  1536
         Uint32 dst_format, void *dst, int dst_pitch)
slouken@11702
  1537
{
slouken@11702
  1538
    int x, y;
slouken@11702
  1539
    const Uint8 *srcY1, *srcY2, *srcU, *srcV;
slouken@11702
  1540
    Uint32 srcY_pitch, srcUV_pitch;
slouken@11702
  1541
    Uint32 srcY_pitch_left, srcUV_pitch_left, srcUV_pixel_stride;
slouken@11702
  1542
    Uint8 *dstY1, *dstY2, *dstU1, *dstU2, *dstV1, *dstV2;
slouken@11702
  1543
    Uint32 dstY_pitch, dstUV_pitch;
slouken@11702
  1544
    Uint32 dst_pitch_left;
slouken@11702
  1545
slouken@11702
  1546
    if (src == dst) {
slouken@11702
  1547
        return SDL_SetError("Can't change YUV plane types in-place");
slouken@11702
  1548
    }
slouken@11702
  1549
slouken@11702
  1550
    if (GetYUVPlanes(width, height, src_format, src, src_pitch,
slouken@11702
  1551
                     &srcY1, &srcU, &srcV, &srcY_pitch, &srcUV_pitch) < 0) {
slouken@11702
  1552
        return -1;
slouken@11702
  1553
    }
slouken@11702
  1554
    srcY2 = srcY1 + srcY_pitch;
slouken@11702
  1555
    srcY_pitch_left = (srcY_pitch - width);
slouken@11702
  1556
slouken@11702
  1557
    if (src_format == SDL_PIXELFORMAT_NV12 || src_format == SDL_PIXELFORMAT_NV21) {
slouken@11702
  1558
        srcUV_pixel_stride = 2;
slouken@11702
  1559
        srcUV_pitch_left = (srcUV_pitch - 2*((width + 1)/2));
slouken@11702
  1560
    } else {
slouken@11702
  1561
        srcUV_pixel_stride = 1;
slouken@11702
  1562
        srcUV_pitch_left = (srcUV_pitch - ((width + 1)/2));
slouken@11702
  1563
    }
slouken@11702
  1564
slouken@11702
  1565
    if (GetYUVPlanes(width, height, dst_format, dst, dst_pitch,
slouken@11702
  1566
                     (const Uint8 **)&dstY1, (const Uint8 **)&dstU1, (const Uint8 **)&dstV1,
slouken@11702
  1567
                     &dstY_pitch, &dstUV_pitch) < 0) {
slouken@11702
  1568
        return -1;
slouken@11702
  1569
    }
slouken@11702
  1570
    dstY2 = dstY1 + dstY_pitch;
slouken@11702
  1571
    dstU2 = dstU1 + dstUV_pitch;
slouken@11702
  1572
    dstV2 = dstV1 + dstUV_pitch;
slouken@11702
  1573
    dst_pitch_left = (dstY_pitch - 4*((width + 1)/2));
slouken@11702
  1574
slouken@11702
  1575
    /* Copy 2x2 blocks of pixels at a time */
slouken@11702
  1576
    for (y = 0; y < (height - 1); y += 2) {
slouken@11702
  1577
        for (x = 0; x < (width - 1); x += 2) {
slouken@11702
  1578
            /* Row 1 */
slouken@11702
  1579
            *dstY1 = *srcY1++;
slouken@11702
  1580
            dstY1 += 2;
slouken@11702
  1581
            *dstY1 = *srcY1++;
slouken@11702
  1582
            dstY1 += 2;
slouken@11702
  1583
            *dstU1 = *srcU;
slouken@11702
  1584
            *dstV1 = *srcV;
slouken@11702
  1585
slouken@11702
  1586
            /* Row 2 */
slouken@11702
  1587
            *dstY2 = *srcY2++;
slouken@11702
  1588
            dstY2 += 2;
slouken@11702
  1589
            *dstY2 = *srcY2++;
slouken@11702
  1590
            dstY2 += 2;
slouken@11702
  1591
            *dstU2 = *srcU;
slouken@11702
  1592
            *dstV2 = *srcV;
slouken@11702
  1593
slouken@11702
  1594
            srcU += srcUV_pixel_stride;
slouken@11702
  1595
            srcV += srcUV_pixel_stride;
slouken@11702
  1596
            dstU1 += 4;
slouken@11702
  1597
            dstU2 += 4;
slouken@11702
  1598
            dstV1 += 4;
slouken@11702
  1599
            dstV2 += 4;
slouken@11702
  1600
        }
slouken@11702
  1601
slouken@11702
  1602
        /* Last column */
slouken@11702
  1603
        if (x == (width - 1)) {
slouken@11702
  1604
            /* Row 1 */
slouken@11702
  1605
            *dstY1 = *srcY1;
slouken@11702
  1606
            dstY1 += 2;
slouken@11702
  1607
            *dstY1 = *srcY1++;
slouken@11702
  1608
            dstY1 += 2;
slouken@11702
  1609
            *dstU1 = *srcU;
slouken@11702
  1610
            *dstV1 = *srcV;
slouken@11702
  1611
slouken@11702
  1612
            /* Row 2 */
slouken@11702
  1613
            *dstY2 = *srcY2;
slouken@11702
  1614
            dstY2 += 2;
slouken@11702
  1615
            *dstY2 = *srcY2++;
slouken@11702
  1616
            dstY2 += 2;
slouken@11702
  1617
            *dstU2 = *srcU;
slouken@11702
  1618
            *dstV2 = *srcV;
slouken@11702
  1619
slouken@11702
  1620
            srcU += srcUV_pixel_stride;
slouken@11702
  1621
            srcV += srcUV_pixel_stride;
slouken@11702
  1622
            dstU1 += 4;
slouken@11702
  1623
            dstU2 += 4;
slouken@11702
  1624
            dstV1 += 4;
slouken@11702
  1625
            dstV2 += 4;
slouken@11702
  1626
        }
slouken@11702
  1627
slouken@11702
  1628
        srcY1 += srcY_pitch_left + srcY_pitch;
slouken@11702
  1629
        srcY2 += srcY_pitch_left + srcY_pitch;
slouken@11702
  1630
        srcU += srcUV_pitch_left;
slouken@11702
  1631
        srcV += srcUV_pitch_left;
slouken@11702
  1632
        dstY1 += dst_pitch_left + dstY_pitch;
slouken@11702
  1633
        dstY2 += dst_pitch_left + dstY_pitch;
slouken@11702
  1634
        dstU1 += dst_pitch_left + dstUV_pitch;
slouken@11702
  1635
        dstU2 += dst_pitch_left + dstUV_pitch;
slouken@11702
  1636
        dstV1 += dst_pitch_left + dstUV_pitch;
slouken@11702
  1637
        dstV2 += dst_pitch_left + dstUV_pitch;
slouken@11702
  1638
    }
slouken@11702
  1639
slouken@11702
  1640
    /* Last row */
slouken@11702
  1641
    if (y == (height - 1)) {
slouken@11702
  1642
        for (x = 0; x < (width - 1); x += 2) {
slouken@11702
  1643
            /* Row 1 */
slouken@11702
  1644
            *dstY1 = *srcY1++;
slouken@11702
  1645
            dstY1 += 2;
slouken@11702
  1646
            *dstY1 = *srcY1++;
slouken@11702
  1647
            dstY1 += 2;
slouken@11702
  1648
            *dstU1 = *srcU;
slouken@11702
  1649
            *dstV1 = *srcV;
slouken@11702
  1650
slouken@11702
  1651
            srcU += srcUV_pixel_stride;
slouken@11702
  1652
            srcV += srcUV_pixel_stride;
slouken@11702
  1653
            dstU1 += 4;
slouken@11702
  1654
            dstV1 += 4;
slouken@11702
  1655
        }
slouken@11702
  1656
slouken@11702
  1657
        /* Last column */
slouken@11702
  1658
        if (x == (width - 1)) {
slouken@11702
  1659
            /* Row 1 */
slouken@11702
  1660
            *dstY1 = *srcY1;
slouken@11702
  1661
            dstY1 += 2;
slouken@11702
  1662
            *dstY1 = *srcY1++;
slouken@11702
  1663
            dstY1 += 2;
slouken@11702
  1664
            *dstU1 = *srcU;
slouken@11702
  1665
            *dstV1 = *srcV;
slouken@11702
  1666
slouken@11702
  1667
            srcU += srcUV_pixel_stride;
slouken@11702
  1668
            srcV += srcUV_pixel_stride;
slouken@11702
  1669
            dstU1 += 4;
slouken@11702
  1670
            dstV1 += 4;
slouken@11702
  1671
        }
slouken@11702
  1672
    }
slouken@11702
  1673
    return 0;
slouken@11702
  1674
}
slouken@11702
  1675
slouken@11702
  1676
static int
slouken@11702
  1677
SDL_ConvertPixels_Packed4_to_Planar2x2(int width, int height,
slouken@11702
  1678
         Uint32 src_format, const void *src, int src_pitch,
slouken@11702
  1679
         Uint32 dst_format, void *dst, int dst_pitch)
slouken@11702
  1680
{
slouken@11702
  1681
    int x, y;
slouken@11702
  1682
    const Uint8 *srcY1, *srcY2, *srcU1, *srcU2, *srcV1, *srcV2;
slouken@11702
  1683
    Uint32 srcY_pitch, srcUV_pitch;
slouken@11702
  1684
    Uint32 src_pitch_left;
slouken@11702
  1685
    Uint8 *dstY1, *dstY2, *dstU, *dstV;
slouken@11702
  1686
    Uint32 dstY_pitch, dstUV_pitch;
slouken@11702
  1687
    Uint32 dstY_pitch_left, dstUV_pitch_left, dstUV_pixel_stride;
slouken@11702
  1688
slouken@11702
  1689
    if (src == dst) {
slouken@11702
  1690
        return SDL_SetError("Can't change YUV plane types in-place");
slouken@11702
  1691
    }
slouken@11702
  1692
slouken@11702
  1693
    if (GetYUVPlanes(width, height, src_format, src, src_pitch,
slouken@11702
  1694
                     &srcY1, &srcU1, &srcV1, &srcY_pitch, &srcUV_pitch) < 0) {
slouken@11702
  1695
        return -1;
slouken@11702
  1696
    }
slouken@11702
  1697
    srcY2 = srcY1 + srcY_pitch;
slouken@11702
  1698
    srcU2 = srcU1 + srcUV_pitch;
slouken@11702
  1699
    srcV2 = srcV1 + srcUV_pitch;
slouken@11702
  1700
    src_pitch_left = (srcY_pitch - 4*((width + 1)/2));
slouken@11702
  1701
slouken@11702
  1702
    if (GetYUVPlanes(width, height, dst_format, dst, dst_pitch,
slouken@11702
  1703
                     (const Uint8 **)&dstY1, (const Uint8 **)&dstU, (const Uint8 **)&dstV,
slouken@11702
  1704
                     &dstY_pitch, &dstUV_pitch) < 0) {
slouken@11702
  1705
        return -1;
slouken@11702
  1706
    }
slouken@11702
  1707
    dstY2 = dstY1 + dstY_pitch;
slouken@11702
  1708
    dstY_pitch_left = (dstY_pitch - width);
slouken@11702
  1709
slouken@11702
  1710
    if (dst_format == SDL_PIXELFORMAT_NV12 || dst_format == SDL_PIXELFORMAT_NV21) {
slouken@11702
  1711
        dstUV_pixel_stride = 2;
slouken@11702
  1712
        dstUV_pitch_left = (dstUV_pitch - 2*((width + 1)/2));
slouken@11702
  1713
    } else {
slouken@11702
  1714
        dstUV_pixel_stride = 1;
slouken@11702
  1715
        dstUV_pitch_left = (dstUV_pitch - ((width + 1)/2));
slouken@11702
  1716
    }
slouken@11702
  1717
slouken@11702
  1718
    /* Copy 2x2 blocks of pixels at a time */
slouken@11702
  1719
    for (y = 0; y < (height - 1); y += 2) {
slouken@11702
  1720
        for (x = 0; x < (width - 1); x += 2) {
slouken@11702
  1721
            /* Row 1 */
slouken@11702
  1722
            *dstY1++ = *srcY1;
slouken@11702
  1723
            srcY1 += 2;
slouken@11702
  1724
            *dstY1++ = *srcY1;
slouken@11702
  1725
            srcY1 += 2;
slouken@11702
  1726
slouken@11702
  1727
            /* Row 2 */
slouken@11702
  1728
            *dstY2++ = *srcY2;
slouken@11702
  1729
            srcY2 += 2;
slouken@11702
  1730
            *dstY2++ = *srcY2;
slouken@11702
  1731
            srcY2 += 2;
slouken@11702
  1732
slouken@11702
  1733
            *dstU = (Uint8)(((Uint32)*srcU1 + *srcU2)/2);
slouken@11702
  1734
            *dstV = (Uint8)(((Uint32)*srcV1 + *srcV2)/2);
slouken@11702
  1735
slouken@11702
  1736
            srcU1 += 4;
slouken@11702
  1737
            srcU2 += 4;
slouken@11702
  1738
            srcV1 += 4;
slouken@11702
  1739
            srcV2 += 4;
slouken@11702
  1740
            dstU += dstUV_pixel_stride;
slouken@11702
  1741
            dstV += dstUV_pixel_stride;
slouken@11702
  1742
        }
slouken@11702
  1743
slouken@11702
  1744
        /* Last column */
slouken@11702
  1745
        if (x == (width - 1)) {
slouken@11702
  1746
            /* Row 1 */
slouken@11702
  1747
            *dstY1 = *srcY1;
slouken@11702
  1748
            srcY1 += 2;
slouken@11702
  1749
            *dstY1++ = *srcY1;
slouken@11702
  1750
            srcY1 += 2;
slouken@11702
  1751
slouken@11702
  1752
            /* Row 2 */
slouken@11702
  1753
            *dstY2 = *srcY2;
slouken@11702
  1754
            srcY2 += 2;
slouken@11702
  1755
            *dstY2++ = *srcY2;
slouken@11702
  1756
            srcY2 += 2;
slouken@11702
  1757
slouken@11702
  1758
            *dstU = (Uint8)(((Uint32)*srcU1 + *srcU2)/2);
slouken@11702
  1759
            *dstV = (Uint8)(((Uint32)*srcV1 + *srcV2)/2);
slouken@11702
  1760
slouken@11702
  1761
            srcU1 += 4;
slouken@11702
  1762
            srcU2 += 4;
slouken@11702
  1763
            srcV1 += 4;
slouken@11702
  1764
            srcV2 += 4;
slouken@11702
  1765
            dstU += dstUV_pixel_stride;
slouken@11702
  1766
            dstV += dstUV_pixel_stride;
slouken@11702
  1767
        }
slouken@11702
  1768
slouken@11702
  1769
        srcY1 += src_pitch_left + srcY_pitch;
slouken@11702
  1770
        srcY2 += src_pitch_left + srcY_pitch;
slouken@11702
  1771
        srcU1 += src_pitch_left + srcUV_pitch;
slouken@11702
  1772
        srcU2 += src_pitch_left + srcUV_pitch;
slouken@11702
  1773
        srcV1 += src_pitch_left + srcUV_pitch;
slouken@11702
  1774
        srcV2 += src_pitch_left + srcUV_pitch;
slouken@11702
  1775
        dstY1 += dstY_pitch_left + dstY_pitch;
slouken@11702
  1776
        dstY2 += dstY_pitch_left + dstY_pitch;
slouken@11702
  1777
        dstU += dstUV_pitch_left;
slouken@11702
  1778
        dstV += dstUV_pitch_left;
slouken@11702
  1779
    }
slouken@11702
  1780
slouken@11702
  1781
    /* Last row */
slouken@11702
  1782
    if (y == (height - 1)) {
slouken@11702
  1783
        for (x = 0; x < (width - 1); x += 2) {
slouken@11702
  1784
            *dstY1++ = *srcY1;
slouken@11702
  1785
            srcY1 += 2;
slouken@11702
  1786
            *dstY1++ = *srcY1;
slouken@11702
  1787
            srcY1 += 2;
slouken@11702
  1788
slouken@11702
  1789
            *dstU = *srcU1;
slouken@11702
  1790
            *dstV = *srcV1;
slouken@11702
  1791
slouken@11702
  1792
            srcU1 += 4;
slouken@11702
  1793
            srcV1 += 4;
slouken@11702
  1794
            dstU += dstUV_pixel_stride;
slouken@11702
  1795
            dstV += dstUV_pixel_stride;
slouken@11702
  1796
        }
slouken@11702
  1797
slouken@11702
  1798
        /* Last column */
slouken@11702
  1799
        if (x == (width - 1)) {
slouken@11702
  1800
            *dstY1 = *srcY1;
slouken@11702
  1801
            *dstU = *srcU1;
slouken@11702
  1802
            *dstV = *srcV1;
slouken@11702
  1803
        }
slouken@11702
  1804
    }
slouken@11702
  1805
    return 0;
slouken@11702
  1806
}
slouken@11702
  1807
slouken@11702
  1808
int
slouken@11702
  1809
SDL_ConvertPixels_YUV_to_YUV(int width, int height,
slouken@11702
  1810
         Uint32 src_format, const void *src, int src_pitch,
slouken@11702
  1811
         Uint32 dst_format, void *dst, int dst_pitch)
slouken@11702
  1812
{
slouken@11702
  1813
    if (src_format == dst_format) {
slouken@11702
  1814
        if (src == dst) {
slouken@11702
  1815
            /* Nothing to do */
slouken@11702
  1816
            return 0;
slouken@11702
  1817
        }
slouken@11702
  1818
        return SDL_ConvertPixels_YUV_to_YUV_Copy(width, height, src_format, src, src_pitch, dst, dst_pitch);
slouken@11702
  1819
    }
slouken@11702
  1820
slouken@11702
  1821
    if (IsPlanar2x2Format(src_format) && IsPlanar2x2Format(dst_format)) {
slouken@11702
  1822
        return SDL_ConvertPixels_Planar2x2_to_Planar2x2(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
slouken@11702
  1823
    } else if (IsPacked4Format(src_format) && IsPacked4Format(dst_format)) {
slouken@11702
  1824
        return SDL_ConvertPixels_Packed4_to_Packed4(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
slouken@11702
  1825
    } else if (IsPlanar2x2Format(src_format) && IsPacked4Format(dst_format)) {
slouken@11702
  1826
        return SDL_ConvertPixels_Planar2x2_to_Packed4(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
slouken@11702
  1827
    } else if (IsPacked4Format(src_format) && IsPlanar2x2Format(dst_format)) {
slouken@11702
  1828
        return SDL_ConvertPixels_Packed4_to_Planar2x2(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
slouken@11702
  1829
    } else {
slouken@11702
  1830
        return SDL_SetError("SDL_ConvertPixels_YUV_to_YUV: Unsupported YUV conversion: %s -> %s", SDL_GetPixelFormatName(src_format), SDL_GetPixelFormatName(dst_format));
slouken@11702
  1831
    }
slouken@11702
  1832
}
slouken@11702
  1833
slouken@11702
  1834
/* vi: set ts=4 sw=4 expandtab: */