| 1 | /* | 
| 2 |   Simple DirectMedia Layer | 
| 3 |   Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org> | 
| 4 |  | 
| 5 |   This software is provided 'as-is', without any express or implied | 
| 6 |   warranty.  In no event will the authors be held liable for any damages | 
| 7 |   arising from the use of this software. | 
| 8 |  | 
| 9 |   Permission is granted to anyone to use this software for any purpose, | 
| 10 |   including commercial applications, and to alter it and redistribute it | 
| 11 |   freely, subject to the following restrictions: | 
| 12 |  | 
| 13 |   1. The origin of this software must not be misrepresented; you must not | 
| 14 |      claim that you wrote the original software. If you use this software | 
| 15 |      in a product, an acknowledgment in the product documentation would be | 
| 16 |      appreciated but is not required. | 
| 17 |   2. Altered source versions must be plainly marked as such, and must not be | 
| 18 |      misrepresented as being the original software. | 
| 19 |   3. This notice may not be removed or altered from any source distribution. | 
| 20 | */ | 
| 21 | #include "SDL_internal.h" | 
| 22 |  | 
| 23 | #include "SDL_pixels_c.h" | 
| 24 | #include "SDL_yuv_c.h" | 
| 25 |  | 
| 26 | #include "yuv2rgb/yuv_rgb.h" | 
| 27 |  | 
| 28 |  | 
| 29 | #ifdef SDL_HAVE_YUV | 
| 30 | static bool IsPlanar2x2Format(SDL_PixelFormat format); | 
| 31 | #endif | 
| 32 |  | 
| 33 | /* | 
| 34 |  * Calculate YUV size and pitch. Check for overflow. | 
| 35 |  * Output 'pitch' that can be used with SDL_ConvertPixels() | 
| 36 |  */ | 
| 37 | bool SDL_CalculateYUVSize(SDL_PixelFormat format, int w, int h, size_t *size, size_t *pitch) | 
| 38 | { | 
| 39 | #ifdef SDL_HAVE_YUV | 
| 40 |     int sz_plane = 0, sz_plane_chroma = 0, sz_plane_packed = 0; | 
| 41 |  | 
| 42 |     if (IsPlanar2x2Format(format) == true) { | 
| 43 |         { | 
| 44 |             /* sz_plane == w * h; */ | 
| 45 |             size_t s1; | 
| 46 |             if (!SDL_size_mul_check_overflow(w, h, &s1)) { | 
| 47 |                 return SDL_SetError("width * height would overflow" ); | 
| 48 |             } | 
| 49 |             sz_plane = (int) s1; | 
| 50 |         } | 
| 51 |  | 
| 52 |         { | 
| 53 |             /* sz_plane_chroma == ((w + 1) / 2) * ((h + 1) / 2); */ | 
| 54 |             size_t s1, s2, s3; | 
| 55 |             if (!SDL_size_add_check_overflow(w, 1, &s1)) { | 
| 56 |                 return SDL_SetError("width + 1 would overflow" ); | 
| 57 |             } | 
| 58 |             s1 = s1 / 2; | 
| 59 |             if (!SDL_size_add_check_overflow(h, 1, &s2)) { | 
| 60 |                 return SDL_SetError("height + 1 would overflow" ); | 
| 61 |             } | 
| 62 |             s2 = s2 / 2; | 
| 63 |             if (!SDL_size_mul_check_overflow(s1, s2, &s3)) { | 
| 64 |                 return SDL_SetError("width * height would overflow" ); | 
| 65 |             } | 
| 66 |             sz_plane_chroma = (int) s3; | 
| 67 |         } | 
| 68 |     } else { | 
| 69 |         /* sz_plane_packed == ((w + 1) / 2) * h; */ | 
| 70 |         size_t s1, s2; | 
| 71 |         if (!SDL_size_add_check_overflow(w, 1, &s1)) { | 
| 72 |             return SDL_SetError("width + 1 would overflow" ); | 
| 73 |         } | 
| 74 |         s1 = s1 / 2; | 
| 75 |         if (!SDL_size_mul_check_overflow(s1, h, &s2)) { | 
| 76 |             return SDL_SetError("width * height would overflow" ); | 
| 77 |         } | 
| 78 |         sz_plane_packed = (int) s2; | 
| 79 |     } | 
| 80 |  | 
| 81 |     switch (format) { | 
| 82 |     case SDL_PIXELFORMAT_YV12: /**< Planar mode: Y + V + U  (3 planes) */ | 
| 83 |     case SDL_PIXELFORMAT_IYUV: /**< Planar mode: Y + U + V  (3 planes) */ | 
| 84 |  | 
| 85 |         if (pitch) { | 
| 86 |             *pitch = w; | 
| 87 |         } | 
| 88 |  | 
| 89 |         if (size) { | 
| 90 |             // dst_size == sz_plane + sz_plane_chroma + sz_plane_chroma; | 
| 91 |             size_t s1, s2; | 
| 92 |             if (!SDL_size_add_check_overflow(sz_plane, sz_plane_chroma, &s1)) { | 
| 93 |                 return SDL_SetError("Y + U would overflow" ); | 
| 94 |             } | 
| 95 |             if (!SDL_size_add_check_overflow(s1, sz_plane_chroma, &s2)) { | 
| 96 |                 return SDL_SetError("Y + U + V would overflow" ); | 
| 97 |             } | 
| 98 |             *size = (int)s2; | 
| 99 |         } | 
| 100 |         break; | 
| 101 |  | 
| 102 |     case SDL_PIXELFORMAT_YUY2: /**< Packed mode: Y0+U0+Y1+V0 (1 plane) */ | 
| 103 |     case SDL_PIXELFORMAT_UYVY: /**< Packed mode: U0+Y0+V0+Y1 (1 plane) */ | 
| 104 |     case SDL_PIXELFORMAT_YVYU: /**< Packed mode: Y0+V0+Y1+U0 (1 plane) */ | 
| 105 |  | 
| 106 |         if (pitch) { | 
| 107 |             /* pitch == ((w + 1) / 2) * 4; */ | 
| 108 |            size_t p1, p2; | 
| 109 |            if (!SDL_size_add_check_overflow(w, 1, &p1)) { | 
| 110 |                return SDL_SetError("width + 1 would overflow" ); | 
| 111 |            } | 
| 112 |            p1 = p1 / 2; | 
| 113 |            if (!SDL_size_mul_check_overflow(p1, 4, &p2)) { | 
| 114 |                return SDL_SetError("width * 4 would overflow" ); | 
| 115 |            } | 
| 116 |            *pitch = p2; | 
| 117 |         } | 
| 118 |  | 
| 119 |         if (size) { | 
| 120 |             /* dst_size == 4 * sz_plane_packed; */ | 
| 121 |             size_t s1; | 
| 122 |             if (!SDL_size_mul_check_overflow(sz_plane_packed, 4, &s1)) { | 
| 123 |                 return SDL_SetError("plane * 4 would overflow" ); | 
| 124 |             } | 
| 125 |             *size = (int) s1; | 
| 126 |         } | 
| 127 |         break; | 
| 128 |  | 
| 129 |     case SDL_PIXELFORMAT_NV12: /**< Planar mode: Y + U/V interleaved  (2 planes) */ | 
| 130 |     case SDL_PIXELFORMAT_NV21: /**< Planar mode: Y + V/U interleaved  (2 planes) */ | 
| 131 |         if (pitch) { | 
| 132 |             *pitch = w; | 
| 133 |         } | 
| 134 |  | 
| 135 |         if (size) { | 
| 136 |             // dst_size == sz_plane + sz_plane_chroma + sz_plane_chroma; | 
| 137 |             size_t s1, s2; | 
| 138 |             if (!SDL_size_add_check_overflow(sz_plane, sz_plane_chroma, &s1)) { | 
| 139 |                 return SDL_SetError("Y + U would overflow" ); | 
| 140 |             } | 
| 141 |             if (!SDL_size_add_check_overflow(s1, sz_plane_chroma, &s2)) { | 
| 142 |                 return SDL_SetError("Y + U + V would overflow" ); | 
| 143 |             } | 
| 144 |             *size = (int) s2; | 
| 145 |         } | 
| 146 |         break; | 
| 147 |  | 
| 148 |     default: | 
| 149 |         return SDL_Unsupported(); | 
| 150 |     } | 
| 151 |  | 
| 152 |     return true; | 
| 153 | #else | 
| 154 |     return SDL_Unsupported(); | 
| 155 | #endif | 
| 156 | } | 
| 157 |  | 
| 158 | #ifdef SDL_HAVE_YUV | 
| 159 |  | 
| 160 | static bool GetYUVConversionType(SDL_Colorspace colorspace, YCbCrType *yuv_type) | 
| 161 | { | 
| 162 |     if (SDL_ISCOLORSPACE_MATRIX_BT601(colorspace)) { | 
| 163 |         if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) { | 
| 164 |             *yuv_type = YCBCR_601_LIMITED; | 
| 165 |         } else { | 
| 166 |             *yuv_type = YCBCR_601_FULL; | 
| 167 |         } | 
| 168 |         return true; | 
| 169 |     } | 
| 170 |  | 
| 171 |     if (SDL_ISCOLORSPACE_MATRIX_BT709(colorspace)) { | 
| 172 |         if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) { | 
| 173 |             *yuv_type = YCBCR_709_LIMITED; | 
| 174 |         } else { | 
| 175 |             *yuv_type = YCBCR_709_FULL; | 
| 176 |         } | 
| 177 |         return true; | 
| 178 |     } | 
| 179 |  | 
| 180 |     if (SDL_ISCOLORSPACE_MATRIX_BT2020_NCL(colorspace)) { | 
| 181 |         if (SDL_ISCOLORSPACE_FULL_RANGE(colorspace)) { | 
| 182 |             *yuv_type = YCBCR_2020_NCL_FULL; | 
| 183 |             return true; | 
| 184 |         } | 
| 185 |     } | 
| 186 |  | 
| 187 |     return SDL_SetError("Unsupported YUV colorspace" ); | 
| 188 | } | 
| 189 |  | 
| 190 | static bool IsPlanar2x2Format(SDL_PixelFormat format) | 
| 191 | { | 
| 192 |     return format == SDL_PIXELFORMAT_YV12 || format == SDL_PIXELFORMAT_IYUV || format == SDL_PIXELFORMAT_NV12 || format == SDL_PIXELFORMAT_NV21 || format == SDL_PIXELFORMAT_P010; | 
| 193 | } | 
| 194 |  | 
| 195 | static bool IsPacked4Format(Uint32 format) | 
| 196 | { | 
| 197 |     return format == SDL_PIXELFORMAT_YUY2 || format == SDL_PIXELFORMAT_UYVY || format == SDL_PIXELFORMAT_YVYU; | 
| 198 | } | 
| 199 |  | 
| 200 | static bool GetYUVPlanes(int width, int height, SDL_PixelFormat format, const void *yuv, int yuv_pitch, | 
| 201 |                          const Uint8 **y, const Uint8 **u, const Uint8 **v, Uint32 *y_stride, Uint32 *uv_stride) | 
| 202 | { | 
| 203 |     const Uint8 *planes[3] = { NULL, NULL, NULL }; | 
| 204 |     int pitches[3] = { 0, 0, 0 }; | 
| 205 |     int uv_width; | 
| 206 |  | 
| 207 |     switch (format) { | 
| 208 |     case SDL_PIXELFORMAT_YV12: | 
| 209 |     case SDL_PIXELFORMAT_IYUV: | 
| 210 |         pitches[0] = yuv_pitch; | 
| 211 |         pitches[1] = (pitches[0] + 1) / 2; | 
| 212 |         pitches[2] = (pitches[0] + 1) / 2; | 
| 213 |         planes[0] = (const Uint8 *)yuv; | 
| 214 |         planes[1] = planes[0] + pitches[0] * height; | 
| 215 |         planes[2] = planes[1] + pitches[1] * ((height + 1) / 2); | 
| 216 |         break; | 
| 217 |     case SDL_PIXELFORMAT_YUY2: | 
| 218 |     case SDL_PIXELFORMAT_UYVY: | 
| 219 |     case SDL_PIXELFORMAT_YVYU: | 
| 220 |         pitches[0] = yuv_pitch; | 
| 221 |         planes[0] = (const Uint8 *)yuv; | 
| 222 |         break; | 
| 223 |     case SDL_PIXELFORMAT_NV12: | 
| 224 |     case SDL_PIXELFORMAT_NV21: | 
| 225 |         pitches[0] = yuv_pitch; | 
| 226 |         pitches[1] = 2 * ((pitches[0] + 1) / 2); | 
| 227 |         planes[0] = (const Uint8 *)yuv; | 
| 228 |         planes[1] = planes[0] + pitches[0] * height; | 
| 229 |         break; | 
| 230 |     case SDL_PIXELFORMAT_P010: | 
| 231 |         pitches[0] = yuv_pitch; | 
| 232 |         uv_width = ((width + 1) / 2) * 2; | 
| 233 |         pitches[1] = SDL_max(pitches[0], (int)(uv_width * sizeof(Uint16))); | 
| 234 |         planes[0] = (const Uint8 *)yuv; | 
| 235 |         planes[1] = planes[0] + pitches[0] * height; | 
| 236 |         break; | 
| 237 |     default: | 
| 238 |         return SDL_SetError("GetYUVPlanes(): Unsupported YUV format: %s" , SDL_GetPixelFormatName(format)); | 
| 239 |     } | 
| 240 |  | 
| 241 |     switch (format) { | 
| 242 |     case SDL_PIXELFORMAT_YV12: | 
| 243 |         *y = planes[0]; | 
| 244 |         *y_stride = pitches[0]; | 
| 245 |         *v = planes[1]; | 
| 246 |         *u = planes[2]; | 
| 247 |         *uv_stride = pitches[1]; | 
| 248 |         break; | 
| 249 |     case SDL_PIXELFORMAT_IYUV: | 
| 250 |         *y = planes[0]; | 
| 251 |         *y_stride = pitches[0]; | 
| 252 |         *v = planes[2]; | 
| 253 |         *u = planes[1]; | 
| 254 |         *uv_stride = pitches[1]; | 
| 255 |         break; | 
| 256 |     case SDL_PIXELFORMAT_YUY2: | 
| 257 |         *y = planes[0]; | 
| 258 |         *y_stride = pitches[0]; | 
| 259 |         *v = *y + 3; | 
| 260 |         *u = *y + 1; | 
| 261 |         *uv_stride = pitches[0]; | 
| 262 |         break; | 
| 263 |     case SDL_PIXELFORMAT_UYVY: | 
| 264 |         *y = planes[0] + 1; | 
| 265 |         *y_stride = pitches[0]; | 
| 266 |         *v = *y + 1; | 
| 267 |         *u = *y - 1; | 
| 268 |         *uv_stride = pitches[0]; | 
| 269 |         break; | 
| 270 |     case SDL_PIXELFORMAT_YVYU: | 
| 271 |         *y = planes[0]; | 
| 272 |         *y_stride = pitches[0]; | 
| 273 |         *v = *y + 1; | 
| 274 |         *u = *y + 3; | 
| 275 |         *uv_stride = pitches[0]; | 
| 276 |         break; | 
| 277 |     case SDL_PIXELFORMAT_NV12: | 
| 278 |         *y = planes[0]; | 
| 279 |         *y_stride = pitches[0]; | 
| 280 |         *u = planes[1]; | 
| 281 |         *v = *u + 1; | 
| 282 |         *uv_stride = pitches[1]; | 
| 283 |         break; | 
| 284 |     case SDL_PIXELFORMAT_NV21: | 
| 285 |         *y = planes[0]; | 
| 286 |         *y_stride = pitches[0]; | 
| 287 |         *v = planes[1]; | 
| 288 |         *u = *v + 1; | 
| 289 |         *uv_stride = pitches[1]; | 
| 290 |         break; | 
| 291 |     case SDL_PIXELFORMAT_P010: | 
| 292 |         *y = planes[0]; | 
| 293 |         *y_stride = pitches[0]; | 
| 294 |         *u = planes[1]; | 
| 295 |         *v = *u + sizeof(Uint16); | 
| 296 |         *uv_stride = pitches[1]; | 
| 297 |         break; | 
| 298 |     default: | 
| 299 |         // Should have caught this above | 
| 300 |         return SDL_SetError("GetYUVPlanes[2]: Unsupported YUV format: %s" , SDL_GetPixelFormatName(format)); | 
| 301 |     } | 
| 302 |     return true; | 
| 303 | } | 
| 304 |  | 
| 305 | #ifdef SDL_SSE2_INTRINSICS | 
| 306 | static bool SDL_TARGETING("sse2" ) yuv_rgb_sse( | 
| 307 |     SDL_PixelFormat src_format, SDL_PixelFormat dst_format, | 
| 308 |     Uint32 width, Uint32 height, | 
| 309 |     const Uint8 *y, const Uint8 *u, const Uint8 *v, Uint32 y_stride, Uint32 uv_stride, | 
| 310 |     Uint8 *rgb, Uint32 rgb_stride, | 
| 311 |     YCbCrType yuv_type) | 
| 312 | { | 
| 313 |     if (!SDL_HasSSE2()) { | 
| 314 |         return false; | 
| 315 |     } | 
| 316 |  | 
| 317 |     if (src_format == SDL_PIXELFORMAT_YV12 || | 
| 318 |         src_format == SDL_PIXELFORMAT_IYUV) { | 
| 319 |  | 
| 320 |         switch (dst_format) { | 
| 321 |         case SDL_PIXELFORMAT_RGB565: | 
| 322 |             yuv420_rgb565_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 323 |             return true; | 
| 324 |         case SDL_PIXELFORMAT_RGB24: | 
| 325 |             yuv420_rgb24_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 326 |             return true; | 
| 327 |         case SDL_PIXELFORMAT_RGBX8888: | 
| 328 |         case SDL_PIXELFORMAT_RGBA8888: | 
| 329 |             yuv420_rgba_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 330 |             return true; | 
| 331 |         case SDL_PIXELFORMAT_BGRX8888: | 
| 332 |         case SDL_PIXELFORMAT_BGRA8888: | 
| 333 |             yuv420_bgra_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 334 |             return true; | 
| 335 |         case SDL_PIXELFORMAT_XRGB8888: | 
| 336 |         case SDL_PIXELFORMAT_ARGB8888: | 
| 337 |             yuv420_argb_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 338 |             return true; | 
| 339 |         case SDL_PIXELFORMAT_XBGR8888: | 
| 340 |         case SDL_PIXELFORMAT_ABGR8888: | 
| 341 |             yuv420_abgr_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 342 |             return true; | 
| 343 |         default: | 
| 344 |             break; | 
| 345 |         } | 
| 346 |     } | 
| 347 |  | 
| 348 |     if (src_format == SDL_PIXELFORMAT_YUY2 || | 
| 349 |         src_format == SDL_PIXELFORMAT_UYVY || | 
| 350 |         src_format == SDL_PIXELFORMAT_YVYU) { | 
| 351 |  | 
| 352 |         switch (dst_format) { | 
| 353 |         case SDL_PIXELFORMAT_RGB565: | 
| 354 |             yuv422_rgb565_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 355 |             return true; | 
| 356 |         case SDL_PIXELFORMAT_RGB24: | 
| 357 |             yuv422_rgb24_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 358 |             return true; | 
| 359 |         case SDL_PIXELFORMAT_RGBX8888: | 
| 360 |         case SDL_PIXELFORMAT_RGBA8888: | 
| 361 |             yuv422_rgba_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 362 |             return true; | 
| 363 |         case SDL_PIXELFORMAT_BGRX8888: | 
| 364 |         case SDL_PIXELFORMAT_BGRA8888: | 
| 365 |             yuv422_bgra_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 366 |             return true; | 
| 367 |         case SDL_PIXELFORMAT_XRGB8888: | 
| 368 |         case SDL_PIXELFORMAT_ARGB8888: | 
| 369 |             yuv422_argb_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 370 |             return true; | 
| 371 |         case SDL_PIXELFORMAT_XBGR8888: | 
| 372 |         case SDL_PIXELFORMAT_ABGR8888: | 
| 373 |             yuv422_abgr_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 374 |             return true; | 
| 375 |         default: | 
| 376 |             break; | 
| 377 |         } | 
| 378 |     } | 
| 379 |  | 
| 380 |     if (src_format == SDL_PIXELFORMAT_NV12 || | 
| 381 |         src_format == SDL_PIXELFORMAT_NV21) { | 
| 382 |  | 
| 383 |         switch (dst_format) { | 
| 384 |         case SDL_PIXELFORMAT_RGB565: | 
| 385 |             yuvnv12_rgb565_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 386 |             return true; | 
| 387 |         case SDL_PIXELFORMAT_RGB24: | 
| 388 |             yuvnv12_rgb24_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 389 |             return true; | 
| 390 |         case SDL_PIXELFORMAT_RGBX8888: | 
| 391 |         case SDL_PIXELFORMAT_RGBA8888: | 
| 392 |             yuvnv12_rgba_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 393 |             return true; | 
| 394 |         case SDL_PIXELFORMAT_BGRX8888: | 
| 395 |         case SDL_PIXELFORMAT_BGRA8888: | 
| 396 |             yuvnv12_bgra_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 397 |             return true; | 
| 398 |         case SDL_PIXELFORMAT_XRGB8888: | 
| 399 |         case SDL_PIXELFORMAT_ARGB8888: | 
| 400 |             yuvnv12_argb_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 401 |             return true; | 
| 402 |         case SDL_PIXELFORMAT_XBGR8888: | 
| 403 |         case SDL_PIXELFORMAT_ABGR8888: | 
| 404 |             yuvnv12_abgr_sseu(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 405 |             return true; | 
| 406 |         default: | 
| 407 |             break; | 
| 408 |         } | 
| 409 |     } | 
| 410 |     return false; | 
| 411 | } | 
| 412 | #else | 
| 413 | static bool yuv_rgb_sse( | 
| 414 |     SDL_PixelFormat src_format, SDL_PixelFormat dst_format, | 
| 415 |     Uint32 width, Uint32 height, | 
| 416 |     const Uint8 *y, const Uint8 *u, const Uint8 *v, Uint32 y_stride, Uint32 uv_stride, | 
| 417 |     Uint8 *rgb, Uint32 rgb_stride, | 
| 418 |     YCbCrType yuv_type) | 
| 419 | { | 
| 420 |     return false; | 
| 421 | } | 
| 422 | #endif | 
| 423 |  | 
| 424 | #ifdef SDL_LSX_INTRINSICS | 
| 425 | static bool yuv_rgb_lsx( | 
| 426 |     SDL_PixelFormat src_format, SDL_PixelFormat dst_format, | 
| 427 |     Uint32 width, Uint32 height, | 
| 428 |     const Uint8 *y, const Uint8 *u, const Uint8 *v, Uint32 y_stride, Uint32 uv_stride, | 
| 429 |     Uint8 *rgb, Uint32 rgb_stride, | 
| 430 |     YCbCrType yuv_type) | 
| 431 | { | 
| 432 |     if (!SDL_HasLSX()) { | 
| 433 |         return false; | 
| 434 |     } | 
| 435 |     if (src_format == SDL_PIXELFORMAT_YV12 || | 
| 436 |         src_format == SDL_PIXELFORMAT_IYUV) { | 
| 437 |  | 
| 438 |         switch (dst_format) { | 
| 439 |         case SDL_PIXELFORMAT_RGB24: | 
| 440 |             yuv420_rgb24_lsx(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 441 |             return true; | 
| 442 |         case SDL_PIXELFORMAT_RGBX8888: | 
| 443 |         case SDL_PIXELFORMAT_RGBA8888: | 
| 444 |             yuv420_rgba_lsx(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 445 |             return true; | 
| 446 |         case SDL_PIXELFORMAT_BGRX8888: | 
| 447 |         case SDL_PIXELFORMAT_BGRA8888: | 
| 448 |             yuv420_bgra_lsx(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 449 |             return true; | 
| 450 |         case SDL_PIXELFORMAT_XRGB8888: | 
| 451 |         case SDL_PIXELFORMAT_ARGB8888: | 
| 452 |             yuv420_argb_lsx(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 453 |             return true; | 
| 454 |         case SDL_PIXELFORMAT_XBGR8888: | 
| 455 |         case SDL_PIXELFORMAT_ABGR8888: | 
| 456 |             yuv420_abgr_lsx(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 457 |             return true; | 
| 458 |         default: | 
| 459 |             break; | 
| 460 |         } | 
| 461 |     } | 
| 462 |     return false; | 
| 463 | } | 
| 464 | #else | 
| 465 | static bool yuv_rgb_lsx( | 
| 466 |     SDL_PixelFormat src_format, SDL_PixelFormat dst_format, | 
| 467 |     Uint32 width, Uint32 height, | 
| 468 |     const Uint8 *y, const Uint8 *u, const Uint8 *v, Uint32 y_stride, Uint32 uv_stride, | 
| 469 |     Uint8 *rgb, Uint32 rgb_stride, | 
| 470 |     YCbCrType yuv_type) | 
| 471 | { | 
| 472 |     return false; | 
| 473 | } | 
| 474 | #endif | 
| 475 |  | 
| 476 | static bool yuv_rgb_std( | 
| 477 |     SDL_PixelFormat src_format, SDL_PixelFormat dst_format, | 
| 478 |     Uint32 width, Uint32 height, | 
| 479 |     const Uint8 *y, const Uint8 *u, const Uint8 *v, Uint32 y_stride, Uint32 uv_stride, | 
| 480 |     Uint8 *rgb, Uint32 rgb_stride, | 
| 481 |     YCbCrType yuv_type) | 
| 482 | { | 
| 483 |     if (src_format == SDL_PIXELFORMAT_YV12 || | 
| 484 |         src_format == SDL_PIXELFORMAT_IYUV) { | 
| 485 |  | 
| 486 |         switch (dst_format) { | 
| 487 |         case SDL_PIXELFORMAT_RGB565: | 
| 488 |             yuv420_rgb565_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 489 |             return true; | 
| 490 |         case SDL_PIXELFORMAT_RGB24: | 
| 491 |             yuv420_rgb24_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 492 |             return true; | 
| 493 |         case SDL_PIXELFORMAT_RGBX8888: | 
| 494 |         case SDL_PIXELFORMAT_RGBA8888: | 
| 495 |             yuv420_rgba_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 496 |             return true; | 
| 497 |         case SDL_PIXELFORMAT_BGRX8888: | 
| 498 |         case SDL_PIXELFORMAT_BGRA8888: | 
| 499 |             yuv420_bgra_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 500 |             return true; | 
| 501 |         case SDL_PIXELFORMAT_XRGB8888: | 
| 502 |         case SDL_PIXELFORMAT_ARGB8888: | 
| 503 |             yuv420_argb_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 504 |             return true; | 
| 505 |         case SDL_PIXELFORMAT_XBGR8888: | 
| 506 |         case SDL_PIXELFORMAT_ABGR8888: | 
| 507 |             yuv420_abgr_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 508 |             return true; | 
| 509 |         default: | 
| 510 |             break; | 
| 511 |         } | 
| 512 |     } | 
| 513 |  | 
| 514 |     if (src_format == SDL_PIXELFORMAT_YUY2 || | 
| 515 |         src_format == SDL_PIXELFORMAT_UYVY || | 
| 516 |         src_format == SDL_PIXELFORMAT_YVYU) { | 
| 517 |  | 
| 518 |         switch (dst_format) { | 
| 519 |         case SDL_PIXELFORMAT_RGB565: | 
| 520 |             yuv422_rgb565_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 521 |             return true; | 
| 522 |         case SDL_PIXELFORMAT_RGB24: | 
| 523 |             yuv422_rgb24_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 524 |             return true; | 
| 525 |         case SDL_PIXELFORMAT_RGBX8888: | 
| 526 |         case SDL_PIXELFORMAT_RGBA8888: | 
| 527 |             yuv422_rgba_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 528 |             return true; | 
| 529 |         case SDL_PIXELFORMAT_BGRX8888: | 
| 530 |         case SDL_PIXELFORMAT_BGRA8888: | 
| 531 |             yuv422_bgra_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 532 |             return true; | 
| 533 |         case SDL_PIXELFORMAT_XRGB8888: | 
| 534 |         case SDL_PIXELFORMAT_ARGB8888: | 
| 535 |             yuv422_argb_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 536 |             return true; | 
| 537 |         case SDL_PIXELFORMAT_XBGR8888: | 
| 538 |         case SDL_PIXELFORMAT_ABGR8888: | 
| 539 |             yuv422_abgr_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 540 |             return true; | 
| 541 |         default: | 
| 542 |             break; | 
| 543 |         } | 
| 544 |     } | 
| 545 |  | 
| 546 |     if (src_format == SDL_PIXELFORMAT_NV12 || | 
| 547 |         src_format == SDL_PIXELFORMAT_NV21) { | 
| 548 |  | 
| 549 |         switch (dst_format) { | 
| 550 |         case SDL_PIXELFORMAT_RGB565: | 
| 551 |             yuvnv12_rgb565_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 552 |             return true; | 
| 553 |         case SDL_PIXELFORMAT_RGB24: | 
| 554 |             yuvnv12_rgb24_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 555 |             return true; | 
| 556 |         case SDL_PIXELFORMAT_RGBX8888: | 
| 557 |         case SDL_PIXELFORMAT_RGBA8888: | 
| 558 |             yuvnv12_rgba_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 559 |             return true; | 
| 560 |         case SDL_PIXELFORMAT_BGRX8888: | 
| 561 |         case SDL_PIXELFORMAT_BGRA8888: | 
| 562 |             yuvnv12_bgra_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 563 |             return true; | 
| 564 |         case SDL_PIXELFORMAT_XRGB8888: | 
| 565 |         case SDL_PIXELFORMAT_ARGB8888: | 
| 566 |             yuvnv12_argb_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 567 |             return true; | 
| 568 |         case SDL_PIXELFORMAT_XBGR8888: | 
| 569 |         case SDL_PIXELFORMAT_ABGR8888: | 
| 570 |             yuvnv12_abgr_std(width, height, y, u, v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 571 |             return true; | 
| 572 |         default: | 
| 573 |             break; | 
| 574 |         } | 
| 575 |     } | 
| 576 |  | 
| 577 |     if (src_format == SDL_PIXELFORMAT_P010) { | 
| 578 |         switch (dst_format) { | 
| 579 |         case SDL_PIXELFORMAT_XBGR2101010: | 
| 580 |             yuvp010_xbgr2101010_std(width, height, (const uint16_t *)y, (const uint16_t *)u, (const uint16_t *)v, y_stride, uv_stride, rgb, rgb_stride, yuv_type); | 
| 581 |             return true; | 
| 582 |         default: | 
| 583 |             break; | 
| 584 |         } | 
| 585 |     } | 
| 586 |     return false; | 
| 587 | } | 
| 588 |  | 
| 589 | bool SDL_ConvertPixels_YUV_to_RGB(int width, int height, | 
| 590 |                                   SDL_PixelFormat src_format, SDL_Colorspace src_colorspace, SDL_PropertiesID src_properties, const void *src, int src_pitch, | 
| 591 |                                   SDL_PixelFormat dst_format, SDL_Colorspace dst_colorspace, SDL_PropertiesID dst_properties, void *dst, int dst_pitch) | 
| 592 | { | 
| 593 |     const Uint8 *y = NULL; | 
| 594 |     const Uint8 *u = NULL; | 
| 595 |     const Uint8 *v = NULL; | 
| 596 |     Uint32 y_stride = 0; | 
| 597 |     Uint32 uv_stride = 0; | 
| 598 |  | 
| 599 |     if (!GetYUVPlanes(width, height, src_format, src, src_pitch, &y, &u, &v, &y_stride, &uv_stride)) { | 
| 600 |         return false; | 
| 601 |     } | 
| 602 |  | 
| 603 |     if (SDL_COLORSPACEPRIMARIES(src_colorspace) == SDL_COLORSPACEPRIMARIES(dst_colorspace)) { | 
| 604 |         YCbCrType yuv_type = YCBCR_601_LIMITED; | 
| 605 |  | 
| 606 |         if (!GetYUVConversionType(src_colorspace, &yuv_type)) { | 
| 607 |             return false; | 
| 608 |         } | 
| 609 |  | 
| 610 |         if (yuv_rgb_sse(src_format, dst_format, width, height, y, u, v, y_stride, uv_stride, (Uint8 *)dst, dst_pitch, yuv_type)) { | 
| 611 |             return true; | 
| 612 |         } | 
| 613 |  | 
| 614 |         if (yuv_rgb_lsx(src_format, dst_format, width, height, y, u, v, y_stride, uv_stride, (Uint8 *)dst, dst_pitch, yuv_type)) { | 
| 615 |             return true; | 
| 616 |         } | 
| 617 |  | 
| 618 |         if (yuv_rgb_std(src_format, dst_format, width, height, y, u, v, y_stride, uv_stride, (Uint8 *)dst, dst_pitch, yuv_type)) { | 
| 619 |             return true; | 
| 620 |         } | 
| 621 |     } | 
| 622 |  | 
| 623 |     // No fast path for the RGB format, instead convert using an intermediate buffer | 
| 624 |     if (src_format == SDL_PIXELFORMAT_P010 && dst_format != SDL_PIXELFORMAT_XBGR2101010) { | 
| 625 |         bool result; | 
| 626 |         void *tmp; | 
| 627 |         int tmp_pitch = (width * sizeof(Uint32)); | 
| 628 |  | 
| 629 |         tmp = SDL_malloc((size_t)tmp_pitch * height); | 
| 630 |         if (!tmp) { | 
| 631 |             return false; | 
| 632 |         } | 
| 633 |  | 
| 634 |         // convert src/src_format to tmp/XBGR2101010 | 
| 635 |         result = SDL_ConvertPixels_YUV_to_RGB(width, height, src_format, src_colorspace, src_properties, src, src_pitch, SDL_PIXELFORMAT_XBGR2101010, src_colorspace, src_properties, tmp, tmp_pitch); | 
| 636 |         if (!result) { | 
| 637 |             SDL_free(tmp); | 
| 638 |             return false; | 
| 639 |         } | 
| 640 |  | 
| 641 |         // convert tmp/XBGR2101010 to dst/RGB | 
| 642 |         result = SDL_ConvertPixelsAndColorspace(width, height, SDL_PIXELFORMAT_XBGR2101010, src_colorspace, src_properties, tmp, tmp_pitch, dst_format, dst_colorspace, dst_properties, dst, dst_pitch); | 
| 643 |         SDL_free(tmp); | 
| 644 |         return result; | 
| 645 |     } | 
| 646 |  | 
| 647 |     if (dst_format != SDL_PIXELFORMAT_ARGB8888) { | 
| 648 |         bool result; | 
| 649 |         void *tmp; | 
| 650 |         int tmp_pitch = (width * sizeof(Uint32)); | 
| 651 |  | 
| 652 |         tmp = SDL_malloc((size_t)tmp_pitch * height); | 
| 653 |         if (!tmp) { | 
| 654 |             return false; | 
| 655 |         } | 
| 656 |  | 
| 657 |         // convert src/src_format to tmp/ARGB8888 | 
| 658 |         result = SDL_ConvertPixels_YUV_to_RGB(width, height, src_format, src_colorspace, src_properties, src, src_pitch, SDL_PIXELFORMAT_ARGB8888, SDL_COLORSPACE_SRGB, 0, tmp, tmp_pitch); | 
| 659 |         if (!result) { | 
| 660 |             SDL_free(tmp); | 
| 661 |             return false; | 
| 662 |         } | 
| 663 |  | 
| 664 |         // convert tmp/ARGB8888 to dst/RGB | 
| 665 |         result = SDL_ConvertPixelsAndColorspace(width, height, SDL_PIXELFORMAT_ARGB8888, SDL_COLORSPACE_SRGB, 0, tmp, tmp_pitch, dst_format, dst_colorspace, dst_properties, dst, dst_pitch); | 
| 666 |         SDL_free(tmp); | 
| 667 |         return result; | 
| 668 |     } | 
| 669 |  | 
| 670 |     return SDL_SetError("Unsupported YUV conversion" ); | 
| 671 | } | 
| 672 |  | 
| 673 | struct RGB2YUVFactors | 
| 674 | { | 
| 675 |     int y_offset; | 
| 676 |     float y[3]; // Rfactor, Gfactor, Bfactor | 
| 677 |     float u[3]; // Rfactor, Gfactor, Bfactor | 
| 678 |     float v[3]; // Rfactor, Gfactor, Bfactor | 
| 679 | }; | 
| 680 |  | 
| 681 | static struct RGB2YUVFactors RGB2YUVFactorTables[] = { | 
| 682 |     // ITU-T T.871 (JPEG) | 
| 683 |     { | 
| 684 |         0, | 
| 685 |         { 0.2990f, 0.5870f, 0.1140f }, | 
| 686 |         { -0.1687f, -0.3313f, 0.5000f }, | 
| 687 |         { 0.5000f, -0.4187f, -0.0813f }, | 
| 688 |     }, | 
| 689 |     // ITU-R BT.601-7 | 
| 690 |     { | 
| 691 |         16, | 
| 692 |         { 0.2568f, 0.5041f, 0.0979f }, | 
| 693 |         { -0.1482f, -0.2910f, 0.4392f }, | 
| 694 |         { 0.4392f, -0.3678f, -0.0714f }, | 
| 695 |     }, | 
| 696 |     // ITU-R BT.709-6 full range | 
| 697 |     { | 
| 698 |         0, | 
| 699 |         { 0.2126f, 0.7152f, 0.0722f }, | 
| 700 |         { -0.1141f, -0.3839f, 0.498f }, | 
| 701 |         { 0.498f, -0.4524f, -0.0457f }, | 
| 702 |     }, | 
| 703 |     // ITU-R BT.709-6 | 
| 704 |     { | 
| 705 |         16, | 
| 706 |         { 0.1826f, 0.6142f, 0.0620f }, | 
| 707 |         { -0.1006f, -0.3386f, 0.4392f }, | 
| 708 |         { 0.4392f, -0.3989f, -0.0403f }, | 
| 709 |     }, | 
| 710 |     // ITU-R BT.2020 10-bit full range | 
| 711 |     { | 
| 712 |         0, | 
| 713 |         { 0.2627f, 0.6780f, 0.0593f }, | 
| 714 |         { -0.1395f, -0.3600f, 0.4995f }, | 
| 715 |         { 0.4995f, -0.4593f, -0.0402f }, | 
| 716 |     }, | 
| 717 | }; | 
| 718 |  | 
| 719 | static bool SDL_ConvertPixels_XRGB8888_to_YUV(int width, int height, const void *src, int src_pitch, SDL_PixelFormat dst_format, void *dst, int dst_pitch, YCbCrType yuv_type) | 
| 720 | { | 
| 721 |     const int src_pitch_x_2 = src_pitch * 2; | 
| 722 |     const int height_half = height / 2; | 
| 723 |     const int height_remainder = (height & 0x1); | 
| 724 |     const int width_half = width / 2; | 
| 725 |     const int width_remainder = (width & 0x1); | 
| 726 |     int i, j; | 
| 727 |  | 
| 728 |     const struct RGB2YUVFactors *cvt = &RGB2YUVFactorTables[yuv_type]; | 
| 729 |  | 
| 730 | #define MAKE_Y(r, g, b) (Uint8)SDL_clamp(((int)(cvt->y[0] * (r) + cvt->y[1] * (g) + cvt->y[2] * (b) + 0.5f) + cvt->y_offset), 0, 255) | 
| 731 | #define MAKE_U(r, g, b) (Uint8)SDL_clamp(((int)(cvt->u[0] * (r) + cvt->u[1] * (g) + cvt->u[2] * (b) + 0.5f) + 128), 0, 255) | 
| 732 | #define MAKE_V(r, g, b) (Uint8)SDL_clamp(((int)(cvt->v[0] * (r) + cvt->v[1] * (g) + cvt->v[2] * (b) + 0.5f) + 128), 0, 255) | 
| 733 |  | 
| 734 | #define READ_2x2_PIXELS                                                                                     \ | 
| 735 |     const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i];                                                    \ | 
| 736 |     const Uint32 p2 = ((const Uint32 *)curr_row)[2 * i + 1];                                                \ | 
| 737 |     const Uint32 p3 = ((const Uint32 *)next_row)[2 * i];                                                    \ | 
| 738 |     const Uint32 p4 = ((const Uint32 *)next_row)[2 * i + 1];                                                \ | 
| 739 |     const Uint32 r = ((p1 & 0x00ff0000) + (p2 & 0x00ff0000) + (p3 & 0x00ff0000) + (p4 & 0x00ff0000)) >> 18; \ | 
| 740 |     const Uint32 g = ((p1 & 0x0000ff00) + (p2 & 0x0000ff00) + (p3 & 0x0000ff00) + (p4 & 0x0000ff00)) >> 10; \ | 
| 741 |     const Uint32 b = ((p1 & 0x000000ff) + (p2 & 0x000000ff) + (p3 & 0x000000ff) + (p4 & 0x000000ff)) >> 2; | 
| 742 |  | 
| 743 | #define READ_2x1_PIXELS                                             \ | 
| 744 |     const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i];            \ | 
| 745 |     const Uint32 p2 = ((const Uint32 *)next_row)[2 * i];            \ | 
| 746 |     const Uint32 r = ((p1 & 0x00ff0000) + (p2 & 0x00ff0000)) >> 17; \ | 
| 747 |     const Uint32 g = ((p1 & 0x0000ff00) + (p2 & 0x0000ff00)) >> 9;  \ | 
| 748 |     const Uint32 b = ((p1 & 0x000000ff) + (p2 & 0x000000ff)) >> 1; | 
| 749 |  | 
| 750 | #define READ_1x2_PIXELS                                             \ | 
| 751 |     const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i];            \ | 
| 752 |     const Uint32 p2 = ((const Uint32 *)curr_row)[2 * i + 1];        \ | 
| 753 |     const Uint32 r = ((p1 & 0x00ff0000) + (p2 & 0x00ff0000)) >> 17; \ | 
| 754 |     const Uint32 g = ((p1 & 0x0000ff00) + (p2 & 0x0000ff00)) >> 9;  \ | 
| 755 |     const Uint32 b = ((p1 & 0x000000ff) + (p2 & 0x000000ff)) >> 1; | 
| 756 |  | 
| 757 | #define READ_1x1_PIXEL                                  \ | 
| 758 |     const Uint32 p = ((const Uint32 *)curr_row)[2 * i]; \ | 
| 759 |     const Uint32 r = (p & 0x00ff0000) >> 16;            \ | 
| 760 |     const Uint32 g = (p & 0x0000ff00) >> 8;             \ | 
| 761 |     const Uint32 b = (p & 0x000000ff); | 
| 762 |  | 
| 763 | #define READ_TWO_RGB_PIXELS                                  \ | 
| 764 |     const Uint32 p = ((const Uint32 *)curr_row)[2 * i];      \ | 
| 765 |     const Uint32 r = (p & 0x00ff0000) >> 16;                 \ | 
| 766 |     const Uint32 g = (p & 0x0000ff00) >> 8;                  \ | 
| 767 |     const Uint32 b = (p & 0x000000ff);                       \ | 
| 768 |     const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i + 1]; \ | 
| 769 |     const Uint32 r1 = (p1 & 0x00ff0000) >> 16;               \ | 
| 770 |     const Uint32 g1 = (p1 & 0x0000ff00) >> 8;                \ | 
| 771 |     const Uint32 b1 = (p1 & 0x000000ff);                     \ | 
| 772 |     const Uint32 R = (r + r1) / 2;                           \ | 
| 773 |     const Uint32 G = (g + g1) / 2;                           \ | 
| 774 |     const Uint32 B = (b + b1) / 2; | 
| 775 |  | 
| 776 | #define READ_ONE_RGB_PIXEL READ_1x1_PIXEL | 
| 777 |  | 
| 778 |     switch (dst_format) { | 
| 779 |     case SDL_PIXELFORMAT_YV12: | 
| 780 |     case SDL_PIXELFORMAT_IYUV: | 
| 781 |     case SDL_PIXELFORMAT_NV12: | 
| 782 |     case SDL_PIXELFORMAT_NV21: | 
| 783 |     { | 
| 784 |         const Uint8 *curr_row, *next_row; | 
| 785 |  | 
| 786 |         Uint8 *plane_y; | 
| 787 |         Uint8 *plane_u; | 
| 788 |         Uint8 *plane_v; | 
| 789 |         Uint8 *plane_interleaved_uv; | 
| 790 |         Uint32 y_stride, uv_stride, y_skip, uv_skip; | 
| 791 |  | 
| 792 |         if (!GetYUVPlanes(width, height, dst_format, dst, dst_pitch, | 
| 793 |                           (const Uint8 **)&plane_y, (const Uint8 **)&plane_u, (const Uint8 **)&plane_v, | 
| 794 |                           &y_stride, &uv_stride)) { | 
| 795 |             return false; | 
| 796 |         } | 
| 797 |  | 
| 798 |         plane_interleaved_uv = (plane_y + height * y_stride); | 
| 799 |         y_skip = (y_stride - width); | 
| 800 |  | 
| 801 |         curr_row = (const Uint8 *)src; | 
| 802 |  | 
| 803 |         // Write Y plane | 
| 804 |         for (j = 0; j < height; j++) { | 
| 805 |             for (i = 0; i < width; i++) { | 
| 806 |                 const Uint32 p1 = ((const Uint32 *)curr_row)[i]; | 
| 807 |                 const Uint32 r = (p1 & 0x00ff0000) >> 16; | 
| 808 |                 const Uint32 g = (p1 & 0x0000ff00) >> 8; | 
| 809 |                 const Uint32 b = (p1 & 0x000000ff); | 
| 810 |                 *plane_y++ = MAKE_Y(r, g, b); | 
| 811 |             } | 
| 812 |             plane_y += y_skip; | 
| 813 |             curr_row += src_pitch; | 
| 814 |         } | 
| 815 |  | 
| 816 |         curr_row = (const Uint8 *)src; | 
| 817 |         next_row = (const Uint8 *)src; | 
| 818 |         next_row += src_pitch; | 
| 819 |  | 
| 820 |         if (dst_format == SDL_PIXELFORMAT_YV12 || dst_format == SDL_PIXELFORMAT_IYUV) { | 
| 821 |             // Write UV planes, not interleaved | 
| 822 |             uv_skip = (uv_stride - (width + 1) / 2); | 
| 823 |             for (j = 0; j < height_half; j++) { | 
| 824 |                 for (i = 0; i < width_half; i++) { | 
| 825 |                     READ_2x2_PIXELS; | 
| 826 |                     *plane_u++ = MAKE_U(r, g, b); | 
| 827 |                     *plane_v++ = MAKE_V(r, g, b); | 
| 828 |                 } | 
| 829 |                 if (width_remainder) { | 
| 830 |                     READ_2x1_PIXELS; | 
| 831 |                     *plane_u++ = MAKE_U(r, g, b); | 
| 832 |                     *plane_v++ = MAKE_V(r, g, b); | 
| 833 |                 } | 
| 834 |                 plane_u += uv_skip; | 
| 835 |                 plane_v += uv_skip; | 
| 836 |                 curr_row += src_pitch_x_2; | 
| 837 |                 next_row += src_pitch_x_2; | 
| 838 |             } | 
| 839 |             if (height_remainder) { | 
| 840 |                 for (i = 0; i < width_half; i++) { | 
| 841 |                     READ_1x2_PIXELS; | 
| 842 |                     *plane_u++ = MAKE_U(r, g, b); | 
| 843 |                     *plane_v++ = MAKE_V(r, g, b); | 
| 844 |                 } | 
| 845 |                 if (width_remainder) { | 
| 846 |                     READ_1x1_PIXEL; | 
| 847 |                     *plane_u++ = MAKE_U(r, g, b); | 
| 848 |                     *plane_v++ = MAKE_V(r, g, b); | 
| 849 |                 } | 
| 850 |                 plane_u += uv_skip; | 
| 851 |                 plane_v += uv_skip; | 
| 852 |             } | 
| 853 |         } else if (dst_format == SDL_PIXELFORMAT_NV12) { | 
| 854 |             uv_skip = (uv_stride - ((width + 1) / 2) * 2); | 
| 855 |             for (j = 0; j < height_half; j++) { | 
| 856 |                 for (i = 0; i < width_half; i++) { | 
| 857 |                     READ_2x2_PIXELS; | 
| 858 |                     *plane_interleaved_uv++ = MAKE_U(r, g, b); | 
| 859 |                     *plane_interleaved_uv++ = MAKE_V(r, g, b); | 
| 860 |                 } | 
| 861 |                 if (width_remainder) { | 
| 862 |                     READ_2x1_PIXELS; | 
| 863 |                     *plane_interleaved_uv++ = MAKE_U(r, g, b); | 
| 864 |                     *plane_interleaved_uv++ = MAKE_V(r, g, b); | 
| 865 |                 } | 
| 866 |                 plane_interleaved_uv += uv_skip; | 
| 867 |                 curr_row += src_pitch_x_2; | 
| 868 |                 next_row += src_pitch_x_2; | 
| 869 |             } | 
| 870 |             if (height_remainder) { | 
| 871 |                 for (i = 0; i < width_half; i++) { | 
| 872 |                     READ_1x2_PIXELS; | 
| 873 |                     *plane_interleaved_uv++ = MAKE_U(r, g, b); | 
| 874 |                     *plane_interleaved_uv++ = MAKE_V(r, g, b); | 
| 875 |                 } | 
| 876 |                 if (width_remainder) { | 
| 877 |                     READ_1x1_PIXEL; | 
| 878 |                     *plane_interleaved_uv++ = MAKE_U(r, g, b); | 
| 879 |                     *plane_interleaved_uv++ = MAKE_V(r, g, b); | 
| 880 |                 } | 
| 881 |             } | 
| 882 |         } else /* dst_format == SDL_PIXELFORMAT_NV21 */ { | 
| 883 |             uv_skip = (uv_stride - ((width + 1) / 2) * 2); | 
| 884 |             for (j = 0; j < height_half; j++) { | 
| 885 |                 for (i = 0; i < width_half; i++) { | 
| 886 |                     READ_2x2_PIXELS; | 
| 887 |                     *plane_interleaved_uv++ = MAKE_V(r, g, b); | 
| 888 |                     *plane_interleaved_uv++ = MAKE_U(r, g, b); | 
| 889 |                 } | 
| 890 |                 if (width_remainder) { | 
| 891 |                     READ_2x1_PIXELS; | 
| 892 |                     *plane_interleaved_uv++ = MAKE_V(r, g, b); | 
| 893 |                     *plane_interleaved_uv++ = MAKE_U(r, g, b); | 
| 894 |                 } | 
| 895 |                 plane_interleaved_uv += uv_skip; | 
| 896 |                 curr_row += src_pitch_x_2; | 
| 897 |                 next_row += src_pitch_x_2; | 
| 898 |             } | 
| 899 |             if (height_remainder) { | 
| 900 |                 for (i = 0; i < width_half; i++) { | 
| 901 |                     READ_1x2_PIXELS; | 
| 902 |                     *plane_interleaved_uv++ = MAKE_V(r, g, b); | 
| 903 |                     *plane_interleaved_uv++ = MAKE_U(r, g, b); | 
| 904 |                 } | 
| 905 |                 if (width_remainder) { | 
| 906 |                     READ_1x1_PIXEL; | 
| 907 |                     *plane_interleaved_uv++ = MAKE_V(r, g, b); | 
| 908 |                     *plane_interleaved_uv++ = MAKE_U(r, g, b); | 
| 909 |                 } | 
| 910 |             } | 
| 911 |         } | 
| 912 |     } break; | 
| 913 |  | 
| 914 |     case SDL_PIXELFORMAT_YUY2: | 
| 915 |     case SDL_PIXELFORMAT_UYVY: | 
| 916 |     case SDL_PIXELFORMAT_YVYU: | 
| 917 |     { | 
| 918 |         const Uint8 *curr_row = (const Uint8 *)src; | 
| 919 |         Uint8 *plane = (Uint8 *)dst; | 
| 920 |         const int row_size = (4 * ((width + 1) / 2)); | 
| 921 |         int plane_skip; | 
| 922 |  | 
| 923 |         if (dst_pitch < row_size) { | 
| 924 |             return SDL_SetError("Destination pitch is too small, expected at least %d" , row_size); | 
| 925 |         } | 
| 926 |         plane_skip = (dst_pitch - row_size); | 
| 927 |  | 
| 928 |         // Write YUV plane, packed | 
| 929 |         if (dst_format == SDL_PIXELFORMAT_YUY2) { | 
| 930 |             for (j = 0; j < height; j++) { | 
| 931 |                 for (i = 0; i < width_half; i++) { | 
| 932 |                     READ_TWO_RGB_PIXELS; | 
| 933 |                     // Y U Y1 V | 
| 934 |                     *plane++ = MAKE_Y(r, g, b); | 
| 935 |                     *plane++ = MAKE_U(R, G, B); | 
| 936 |                     *plane++ = MAKE_Y(r1, g1, b1); | 
| 937 |                     *plane++ = MAKE_V(R, G, B); | 
| 938 |                 } | 
| 939 |                 if (width_remainder) { | 
| 940 |                     READ_ONE_RGB_PIXEL; | 
| 941 |                     // Y U Y V | 
| 942 |                     *plane++ = MAKE_Y(r, g, b); | 
| 943 |                     *plane++ = MAKE_U(r, g, b); | 
| 944 |                     *plane++ = MAKE_Y(r, g, b); | 
| 945 |                     *plane++ = MAKE_V(r, g, b); | 
| 946 |                 } | 
| 947 |                 plane += plane_skip; | 
| 948 |                 curr_row += src_pitch; | 
| 949 |             } | 
| 950 |         } else if (dst_format == SDL_PIXELFORMAT_UYVY) { | 
| 951 |             for (j = 0; j < height; j++) { | 
| 952 |                 for (i = 0; i < width_half; i++) { | 
| 953 |                     READ_TWO_RGB_PIXELS; | 
| 954 |                     // U Y V Y1 | 
| 955 |                     *plane++ = MAKE_U(R, G, B); | 
| 956 |                     *plane++ = MAKE_Y(r, g, b); | 
| 957 |                     *plane++ = MAKE_V(R, G, B); | 
| 958 |                     *plane++ = MAKE_Y(r1, g1, b1); | 
| 959 |                 } | 
| 960 |                 if (width_remainder) { | 
| 961 |                     READ_ONE_RGB_PIXEL; | 
| 962 |                     // U Y V Y | 
| 963 |                     *plane++ = MAKE_U(r, g, b); | 
| 964 |                     *plane++ = MAKE_Y(r, g, b); | 
| 965 |                     *plane++ = MAKE_V(r, g, b); | 
| 966 |                     *plane++ = MAKE_Y(r, g, b); | 
| 967 |                 } | 
| 968 |                 plane += plane_skip; | 
| 969 |                 curr_row += src_pitch; | 
| 970 |             } | 
| 971 |         } else if (dst_format == SDL_PIXELFORMAT_YVYU) { | 
| 972 |             for (j = 0; j < height; j++) { | 
| 973 |                 for (i = 0; i < width_half; i++) { | 
| 974 |                     READ_TWO_RGB_PIXELS; | 
| 975 |                     // Y V Y1 U | 
| 976 |                     *plane++ = MAKE_Y(r, g, b); | 
| 977 |                     *plane++ = MAKE_V(R, G, B); | 
| 978 |                     *plane++ = MAKE_Y(r1, g1, b1); | 
| 979 |                     *plane++ = MAKE_U(R, G, B); | 
| 980 |                 } | 
| 981 |                 if (width_remainder) { | 
| 982 |                     READ_ONE_RGB_PIXEL; | 
| 983 |                     // Y V Y U | 
| 984 |                     *plane++ = MAKE_Y(r, g, b); | 
| 985 |                     *plane++ = MAKE_V(r, g, b); | 
| 986 |                     *plane++ = MAKE_Y(r, g, b); | 
| 987 |                     *plane++ = MAKE_U(r, g, b); | 
| 988 |                 } | 
| 989 |                 plane += plane_skip; | 
| 990 |                 curr_row += src_pitch; | 
| 991 |             } | 
| 992 |         } | 
| 993 |     } break; | 
| 994 |  | 
| 995 |     default: | 
| 996 |         return SDL_SetError("Unsupported YUV destination format: %s" , SDL_GetPixelFormatName(dst_format)); | 
| 997 |     } | 
| 998 | #undef MAKE_Y | 
| 999 | #undef MAKE_U | 
| 1000 | #undef MAKE_V | 
| 1001 | #undef READ_2x2_PIXELS | 
| 1002 | #undef READ_2x1_PIXELS | 
| 1003 | #undef READ_1x2_PIXELS | 
| 1004 | #undef READ_1x1_PIXEL | 
| 1005 | #undef READ_TWO_RGB_PIXELS | 
| 1006 | #undef READ_ONE_RGB_PIXEL | 
| 1007 |     return true; | 
| 1008 | } | 
| 1009 |  | 
| 1010 | static bool SDL_ConvertPixels_XBGR2101010_to_P010(int width, int height, const void *src, int src_pitch, SDL_PixelFormat dst_format, void *dst, int dst_pitch, YCbCrType yuv_type) | 
| 1011 | { | 
| 1012 |     const int src_pitch_x_2 = src_pitch * 2; | 
| 1013 |     const int height_half = height / 2; | 
| 1014 |     const int height_remainder = (height & 0x1); | 
| 1015 |     const int width_half = width / 2; | 
| 1016 |     const int width_remainder = (width & 0x1); | 
| 1017 |     int i, j; | 
| 1018 |  | 
| 1019 |     const struct RGB2YUVFactors *cvt = &RGB2YUVFactorTables[yuv_type]; | 
| 1020 |  | 
| 1021 | #define MAKE_Y(r, g, b) (Uint16)(((int)(cvt->y[0] * (r) + cvt->y[1] * (g) + cvt->y[2] * (b) + 0.5f) + cvt->y_offset) << 6) | 
| 1022 | #define MAKE_U(r, g, b) (Uint16)(((int)(cvt->u[0] * (r) + cvt->u[1] * (g) + cvt->u[2] * (b) + 0.5f) + 512) << 6) | 
| 1023 | #define MAKE_V(r, g, b) (Uint16)(((int)(cvt->v[0] * (r) + cvt->v[1] * (g) + cvt->v[2] * (b) + 0.5f) + 512) << 6) | 
| 1024 |  | 
| 1025 | #define READ_2x2_PIXELS                                                                                     \ | 
| 1026 |     const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i];                                                    \ | 
| 1027 |     const Uint32 p2 = ((const Uint32 *)curr_row)[2 * i + 1];                                                \ | 
| 1028 |     const Uint32 p3 = ((const Uint32 *)next_row)[2 * i];                                                    \ | 
| 1029 |     const Uint32 p4 = ((const Uint32 *)next_row)[2 * i + 1];                                                \ | 
| 1030 |     const Uint32 r = ((p1 & 0x000003ff) + (p2 & 0x000003ff) + (p3 & 0x000003ff) + (p4 & 0x000003ff)) >> 2;  \ | 
| 1031 |     const Uint32 g = ((p1 & 0x000ffc00) + (p2 & 0x000ffc00) + (p3 & 0x000ffc00) + (p4 & 0x000ffc00)) >> 12; \ | 
| 1032 |     const Uint32 b = ((p1 & 0x3ff00000) + (p2 & 0x3ff00000) + (p3 & 0x3ff00000) + (p4 & 0x3ff00000)) >> 22; | 
| 1033 |  | 
| 1034 | #define READ_2x1_PIXELS                                             \ | 
| 1035 |     const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i];            \ | 
| 1036 |     const Uint32 p2 = ((const Uint32 *)next_row)[2 * i];            \ | 
| 1037 |     const Uint32 r = ((p1 & 0x000003ff) + (p2 & 0x000003ff)) >> 1;  \ | 
| 1038 |     const Uint32 g = ((p1 & 0x000ffc00) + (p2 & 0x000ffc00)) >> 11; \ | 
| 1039 |     const Uint32 b = ((p1 & 0x3ff00000) + (p2 & 0x3ff00000)) >> 21; | 
| 1040 |  | 
| 1041 | #define READ_1x2_PIXELS                                             \ | 
| 1042 |     const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i];            \ | 
| 1043 |     const Uint32 p2 = ((const Uint32 *)curr_row)[2 * i + 1];        \ | 
| 1044 |     const Uint32 r = ((p1 & 0x000003ff) + (p2 & 0x000003ff)) >> 1;  \ | 
| 1045 |     const Uint32 g = ((p1 & 0x000ffc00) + (p2 & 0x000ffc00)) >> 11; \ | 
| 1046 |     const Uint32 b = ((p1 & 0x3ff00000) + (p2 & 0x3ff00000)) >> 21; | 
| 1047 |  | 
| 1048 | #define READ_1x1_PIXEL                                  \ | 
| 1049 |     const Uint32 p = ((const Uint32 *)curr_row)[2 * i]; \ | 
| 1050 |     const Uint32 r = (p & 0x000003ff);                  \ | 
| 1051 |     const Uint32 g = (p & 0x000ffc00) >> 10;            \ | 
| 1052 |     const Uint32 b = (p & 0x3ff00000) >> 20; | 
| 1053 |  | 
| 1054 |     const Uint8 *curr_row, *next_row; | 
| 1055 |  | 
| 1056 |     Uint16 *plane_y; | 
| 1057 |     Uint16 *plane_u; | 
| 1058 |     Uint16 *plane_v; | 
| 1059 |     Uint16 *plane_interleaved_uv; | 
| 1060 |     Uint32 y_stride, uv_stride, y_skip, uv_skip; | 
| 1061 |  | 
| 1062 |     if (!GetYUVPlanes(width, height, dst_format, dst, dst_pitch, | 
| 1063 |                       (const Uint8 **)&plane_y, (const Uint8 **)&plane_u, (const Uint8 **)&plane_v, | 
| 1064 |                       &y_stride, &uv_stride)) { | 
| 1065 |         return false; | 
| 1066 |     } | 
| 1067 |  | 
| 1068 |     y_stride /= sizeof(Uint16); | 
| 1069 |     uv_stride /= sizeof(Uint16); | 
| 1070 |  | 
| 1071 |     plane_interleaved_uv = (plane_y + height * y_stride); | 
| 1072 |     y_skip = (y_stride - width); | 
| 1073 |  | 
| 1074 |     curr_row = (const Uint8 *)src; | 
| 1075 |  | 
| 1076 |     // Write Y plane | 
| 1077 |     for (j = 0; j < height; j++) { | 
| 1078 |         for (i = 0; i < width; i++) { | 
| 1079 |             const Uint32 p1 = ((const Uint32 *)curr_row)[i]; | 
| 1080 |             const Uint32 r = (p1 >>  0) & 0x03ff; | 
| 1081 |             const Uint32 g = (p1 >> 10) & 0x03ff; | 
| 1082 |             const Uint32 b = (p1 >> 20) & 0x03ff; | 
| 1083 |             *plane_y++ = MAKE_Y(r, g, b); | 
| 1084 |         } | 
| 1085 |         plane_y += y_skip; | 
| 1086 |         curr_row += src_pitch; | 
| 1087 |     } | 
| 1088 |  | 
| 1089 |     curr_row = (const Uint8 *)src; | 
| 1090 |     next_row = (const Uint8 *)src; | 
| 1091 |     next_row += src_pitch; | 
| 1092 |  | 
| 1093 |     uv_skip = (uv_stride - ((width + 1) / 2) * 2); | 
| 1094 |     for (j = 0; j < height_half; j++) { | 
| 1095 |         for (i = 0; i < width_half; i++) { | 
| 1096 |             READ_2x2_PIXELS; | 
| 1097 |             *plane_interleaved_uv++ = MAKE_U(r, g, b); | 
| 1098 |             *plane_interleaved_uv++ = MAKE_V(r, g, b); | 
| 1099 |         } | 
| 1100 |         if (width_remainder) { | 
| 1101 |             READ_2x1_PIXELS; | 
| 1102 |             *plane_interleaved_uv++ = MAKE_U(r, g, b); | 
| 1103 |             *plane_interleaved_uv++ = MAKE_V(r, g, b); | 
| 1104 |         } | 
| 1105 |         plane_interleaved_uv += uv_skip; | 
| 1106 |         curr_row += src_pitch_x_2; | 
| 1107 |         next_row += src_pitch_x_2; | 
| 1108 |     } | 
| 1109 |     if (height_remainder) { | 
| 1110 |         for (i = 0; i < width_half; i++) { | 
| 1111 |             READ_1x2_PIXELS; | 
| 1112 |             *plane_interleaved_uv++ = MAKE_U(r, g, b); | 
| 1113 |             *plane_interleaved_uv++ = MAKE_V(r, g, b); | 
| 1114 |         } | 
| 1115 |         if (width_remainder) { | 
| 1116 |             READ_1x1_PIXEL; | 
| 1117 |             *plane_interleaved_uv++ = MAKE_U(r, g, b); | 
| 1118 |             *plane_interleaved_uv++ = MAKE_V(r, g, b); | 
| 1119 |         } | 
| 1120 |     } | 
| 1121 |  | 
| 1122 | #undef MAKE_Y | 
| 1123 | #undef MAKE_U | 
| 1124 | #undef MAKE_V | 
| 1125 | #undef READ_2x2_PIXELS | 
| 1126 | #undef READ_2x1_PIXELS | 
| 1127 | #undef READ_1x2_PIXELS | 
| 1128 | #undef READ_1x1_PIXEL | 
| 1129 |     return true; | 
| 1130 | } | 
| 1131 |  | 
| 1132 | bool SDL_ConvertPixels_RGB_to_YUV(int width, int height, | 
| 1133 |                                   SDL_PixelFormat src_format, SDL_Colorspace src_colorspace, SDL_PropertiesID src_properties, const void *src, int src_pitch, | 
| 1134 |                                   SDL_PixelFormat dst_format, SDL_Colorspace dst_colorspace, SDL_PropertiesID dst_properties, void *dst, int dst_pitch) | 
| 1135 | { | 
| 1136 |     YCbCrType yuv_type = YCBCR_601_LIMITED; | 
| 1137 |  | 
| 1138 |     if (!GetYUVConversionType(dst_colorspace, &yuv_type)) { | 
| 1139 |         return false; | 
| 1140 |     } | 
| 1141 |  | 
| 1142 | #if 0 // Doesn't handle odd widths | 
| 1143 |     // RGB24 to FOURCC | 
| 1144 |     if (src_format == SDL_PIXELFORMAT_RGB24) { | 
| 1145 |         Uint8 *y; | 
| 1146 |         Uint8 *u; | 
| 1147 |         Uint8 *v; | 
| 1148 |         Uint32 y_stride; | 
| 1149 |         Uint32 uv_stride; | 
| 1150 |  | 
| 1151 |         if (GetYUVPlanes(width, height, dst_format, dst, dst_pitch, (const Uint8 **)&y, (const Uint8 **)&u, (const Uint8 **)&v, &y_stride, &uv_stride) < 0) { | 
| 1152 |             return false; | 
| 1153 |         } | 
| 1154 |  | 
| 1155 |         rgb24_yuv420_std(width, height, src, src_pitch, y, u, v, y_stride, uv_stride, yuv_type); | 
| 1156 |         return true; | 
| 1157 |     } | 
| 1158 | #endif | 
| 1159 |  | 
| 1160 |     // ARGB8888 to FOURCC | 
| 1161 |     if ((src_format == SDL_PIXELFORMAT_ARGB8888 || src_format == SDL_PIXELFORMAT_XRGB8888) && | 
| 1162 |         SDL_COLORSPACEPRIMARIES(src_colorspace) == SDL_COLORSPACEPRIMARIES(dst_colorspace)) { | 
| 1163 |         return SDL_ConvertPixels_XRGB8888_to_YUV(width, height, src, src_pitch, dst_format, dst, dst_pitch, yuv_type); | 
| 1164 |     } | 
| 1165 |  | 
| 1166 |     if (dst_format == SDL_PIXELFORMAT_P010) { | 
| 1167 |         if (src_format == SDL_PIXELFORMAT_XBGR2101010 && | 
| 1168 |             SDL_COLORSPACEPRIMARIES(src_colorspace) == SDL_COLORSPACEPRIMARIES(dst_colorspace)) { | 
| 1169 |             return SDL_ConvertPixels_XBGR2101010_to_P010(width, height, src, src_pitch, dst_format, dst, dst_pitch, yuv_type); | 
| 1170 |         } | 
| 1171 |  | 
| 1172 |         // We currently only support converting from XBGR2101010 to P010 | 
| 1173 |         bool result; | 
| 1174 |         void *tmp; | 
| 1175 |         int tmp_pitch = (width * sizeof(Uint32)); | 
| 1176 |  | 
| 1177 |         tmp = SDL_malloc((size_t)tmp_pitch * height); | 
| 1178 |         if (!tmp) { | 
| 1179 |             return false; | 
| 1180 |         } | 
| 1181 |  | 
| 1182 |         // convert src/src_format to tmp/XBGR2101010 | 
| 1183 |         result = SDL_ConvertPixelsAndColorspace(width, height, src_format, src_colorspace, src_properties, src, src_pitch, SDL_PIXELFORMAT_XBGR2101010, dst_colorspace, dst_properties, tmp, tmp_pitch); | 
| 1184 |         if (!result) { | 
| 1185 |             SDL_free(tmp); | 
| 1186 |             return false; | 
| 1187 |         } | 
| 1188 |  | 
| 1189 |         // convert tmp/XBGR2101010 to dst/P010 | 
| 1190 |         result = SDL_ConvertPixels_XBGR2101010_to_P010(width, height, tmp, tmp_pitch, dst_format, dst, dst_pitch, yuv_type); | 
| 1191 |         SDL_free(tmp); | 
| 1192 |         return result; | 
| 1193 |     } | 
| 1194 |  | 
| 1195 |     // not ARGB8888 to FOURCC : need an intermediate conversion | 
| 1196 |     { | 
| 1197 |         bool result; | 
| 1198 |         void *tmp; | 
| 1199 |         int tmp_pitch = (width * sizeof(Uint32)); | 
| 1200 |  | 
| 1201 |         tmp = SDL_malloc((size_t)tmp_pitch * height); | 
| 1202 |         if (!tmp) { | 
| 1203 |             return false; | 
| 1204 |         } | 
| 1205 |  | 
| 1206 |         // convert src/src_format to tmp/XRGB8888 | 
| 1207 |         result = SDL_ConvertPixelsAndColorspace(width, height, src_format, src_colorspace, src_properties, src, src_pitch, SDL_PIXELFORMAT_XRGB8888, SDL_COLORSPACE_SRGB, 0, tmp, tmp_pitch); | 
| 1208 |         if (!result) { | 
| 1209 |             SDL_free(tmp); | 
| 1210 |             return false; | 
| 1211 |         } | 
| 1212 |  | 
| 1213 |         // convert tmp/XRGB8888 to dst/FOURCC | 
| 1214 |         result = SDL_ConvertPixels_XRGB8888_to_YUV(width, height, tmp, tmp_pitch, dst_format, dst, dst_pitch, yuv_type); | 
| 1215 |         SDL_free(tmp); | 
| 1216 |         return result; | 
| 1217 |     } | 
| 1218 | } | 
| 1219 |  | 
| 1220 | static bool SDL_ConvertPixels_YUV_to_YUV_Copy(int width, int height, SDL_PixelFormat format, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 1221 | { | 
| 1222 |     int i; | 
| 1223 |  | 
| 1224 |     if (IsPlanar2x2Format(format)) { | 
| 1225 |         // Y plane | 
| 1226 |         for (i = height; i--;) { | 
| 1227 |             SDL_memcpy(dst, src, width); | 
| 1228 |             src = (const Uint8 *)src + src_pitch; | 
| 1229 |             dst = (Uint8 *)dst + dst_pitch; | 
| 1230 |         } | 
| 1231 |  | 
| 1232 |         if (format == SDL_PIXELFORMAT_YV12 || format == SDL_PIXELFORMAT_IYUV) { | 
| 1233 |             // U and V planes are a quarter the size of the Y plane, rounded up | 
| 1234 |             width = (width + 1) / 2; | 
| 1235 |             height = (height + 1) / 2; | 
| 1236 |             src_pitch = (src_pitch + 1) / 2; | 
| 1237 |             dst_pitch = (dst_pitch + 1) / 2; | 
| 1238 |             for (i = height * 2; i--;) { | 
| 1239 |                 SDL_memcpy(dst, src, width); | 
| 1240 |                 src = (const Uint8 *)src + src_pitch; | 
| 1241 |                 dst = (Uint8 *)dst + dst_pitch; | 
| 1242 |             } | 
| 1243 |         } else if (format == SDL_PIXELFORMAT_NV12 || format == SDL_PIXELFORMAT_NV21) { | 
| 1244 |             // U/V plane is half the height of the Y plane, rounded up | 
| 1245 |             height = (height + 1) / 2; | 
| 1246 |             width = ((width + 1) / 2) * 2; | 
| 1247 |             src_pitch = ((src_pitch + 1) / 2) * 2; | 
| 1248 |             dst_pitch = ((dst_pitch + 1) / 2) * 2; | 
| 1249 |             for (i = height; i--;) { | 
| 1250 |                 SDL_memcpy(dst, src, width); | 
| 1251 |                 src = (const Uint8 *)src + src_pitch; | 
| 1252 |                 dst = (Uint8 *)dst + dst_pitch; | 
| 1253 |             } | 
| 1254 |         } else if (format == SDL_PIXELFORMAT_P010) { | 
| 1255 |             // U/V plane is half the height of the Y plane, rounded up | 
| 1256 |             height = (height + 1) / 2; | 
| 1257 |             width = ((width + 1) / 2) * 2; | 
| 1258 |             src_pitch = ((src_pitch + 1) / 2) * 2; | 
| 1259 |             dst_pitch = ((dst_pitch + 1) / 2) * 2; | 
| 1260 |             for (i = height; i--;) { | 
| 1261 |                 SDL_memcpy(dst, src, width * sizeof(Uint16)); | 
| 1262 |                 src = (const Uint8 *)src + src_pitch; | 
| 1263 |                 dst = (Uint8 *)dst + dst_pitch; | 
| 1264 |             } | 
| 1265 |         } | 
| 1266 |         return true; | 
| 1267 |     } | 
| 1268 |  | 
| 1269 |     if (IsPacked4Format(format)) { | 
| 1270 |         // Packed planes | 
| 1271 |         width = 4 * ((width + 1) / 2); | 
| 1272 |         for (i = height; i--;) { | 
| 1273 |             SDL_memcpy(dst, src, width); | 
| 1274 |             src = (const Uint8 *)src + src_pitch; | 
| 1275 |             dst = (Uint8 *)dst + dst_pitch; | 
| 1276 |         } | 
| 1277 |         return true; | 
| 1278 |     } | 
| 1279 |  | 
| 1280 |     return SDL_SetError("SDL_ConvertPixels_YUV_to_YUV_Copy: Unsupported YUV format: %s" , SDL_GetPixelFormatName(format)); | 
| 1281 | } | 
| 1282 |  | 
| 1283 | static bool SDL_ConvertPixels_SwapUVPlanes(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 1284 | { | 
| 1285 |     int y; | 
| 1286 |     const int UVwidth = (width + 1) / 2; | 
| 1287 |     const int UVheight = (height + 1) / 2; | 
| 1288 |  | 
| 1289 |     // Skip the Y plane | 
| 1290 |     src = (const Uint8 *)src + height * src_pitch; | 
| 1291 |     dst = (Uint8 *)dst + height * dst_pitch; | 
| 1292 |  | 
| 1293 |     if (src == dst) { | 
| 1294 |         int UVpitch = (dst_pitch + 1) / 2; | 
| 1295 |         Uint8 *tmp; | 
| 1296 |         Uint8 *row1 = (Uint8 *)dst; | 
| 1297 |         Uint8 *row2 = row1 + UVheight * UVpitch; | 
| 1298 |  | 
| 1299 |         // Allocate a temporary row for the swap | 
| 1300 |         tmp = (Uint8 *)SDL_malloc(UVwidth); | 
| 1301 |         if (!tmp) { | 
| 1302 |             return false; | 
| 1303 |         } | 
| 1304 |         for (y = 0; y < UVheight; ++y) { | 
| 1305 |             SDL_memcpy(tmp, row1, UVwidth); | 
| 1306 |             SDL_memcpy(row1, row2, UVwidth); | 
| 1307 |             SDL_memcpy(row2, tmp, UVwidth); | 
| 1308 |             row1 += UVpitch; | 
| 1309 |             row2 += UVpitch; | 
| 1310 |         } | 
| 1311 |         SDL_free(tmp); | 
| 1312 |     } else { | 
| 1313 |         const Uint8 *srcUV; | 
| 1314 |         Uint8 *dstUV; | 
| 1315 |         int srcUVPitch = ((src_pitch + 1) / 2); | 
| 1316 |         int dstUVPitch = ((dst_pitch + 1) / 2); | 
| 1317 |  | 
| 1318 |         // Copy the first plane | 
| 1319 |         srcUV = (const Uint8 *)src; | 
| 1320 |         dstUV = (Uint8 *)dst + UVheight * dstUVPitch; | 
| 1321 |         for (y = 0; y < UVheight; ++y) { | 
| 1322 |             SDL_memcpy(dstUV, srcUV, UVwidth); | 
| 1323 |             srcUV += srcUVPitch; | 
| 1324 |             dstUV += dstUVPitch; | 
| 1325 |         } | 
| 1326 |  | 
| 1327 |         // Copy the second plane | 
| 1328 |         dstUV = (Uint8 *)dst; | 
| 1329 |         for (y = 0; y < UVheight; ++y) { | 
| 1330 |             SDL_memcpy(dstUV, srcUV, UVwidth); | 
| 1331 |             srcUV += srcUVPitch; | 
| 1332 |             dstUV += dstUVPitch; | 
| 1333 |         } | 
| 1334 |     } | 
| 1335 |     return true; | 
| 1336 | } | 
| 1337 |  | 
| 1338 | #ifdef SDL_SSE2_INTRINSICS | 
| 1339 | static bool SDL_TARGETING("sse2" ) SDL_ConvertPixels_PackUVPlanes_to_NV_SSE2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch, bool reverseUV) | 
| 1340 | { | 
| 1341 |     int x, y; | 
| 1342 |     const int UVwidth = (width + 1) / 2; | 
| 1343 |     const int UVheight = (height + 1) / 2; | 
| 1344 |     const int srcUVPitch = ((src_pitch + 1) / 2); | 
| 1345 |     const int srcUVPitchLeft = srcUVPitch - UVwidth; | 
| 1346 |     const int dstUVPitch = ((dst_pitch + 1) / 2) * 2; | 
| 1347 |     const int dstUVPitchLeft = dstUVPitch - UVwidth * 2; | 
| 1348 |     const Uint8 *src1, *src2; | 
| 1349 |     Uint8 *dstUV; | 
| 1350 |     Uint8 *tmp = NULL; | 
| 1351 |  | 
| 1352 |     // Skip the Y plane | 
| 1353 |     src = (const Uint8 *)src + height * src_pitch; | 
| 1354 |     dst = (Uint8 *)dst + height * dst_pitch; | 
| 1355 |  | 
| 1356 |     if (src == dst) { | 
| 1357 |         // Need to make a copy of the buffer so we don't clobber it while converting | 
| 1358 |         tmp = (Uint8 *)SDL_malloc((size_t)2 * UVheight * srcUVPitch); | 
| 1359 |         if (tmp == NULL) { | 
| 1360 |             return false; | 
| 1361 |         } | 
| 1362 |         SDL_memcpy(tmp, src, (size_t)2 * UVheight * srcUVPitch); | 
| 1363 |         src = tmp; | 
| 1364 |     } | 
| 1365 |  | 
| 1366 |     if (reverseUV) { | 
| 1367 |         src2 = (const Uint8 *)src; | 
| 1368 |         src1 = src2 + UVheight * srcUVPitch; | 
| 1369 |     } else { | 
| 1370 |         src1 = (const Uint8 *)src; | 
| 1371 |         src2 = src1 + UVheight * srcUVPitch; | 
| 1372 |     } | 
| 1373 |     dstUV = (Uint8 *)dst; | 
| 1374 |  | 
| 1375 |     y = UVheight; | 
| 1376 |     while (y--) { | 
| 1377 |         x = UVwidth; | 
| 1378 |         while (x >= 16) { | 
| 1379 |             __m128i u = _mm_loadu_si128((__m128i *)src1); | 
| 1380 |             __m128i v = _mm_loadu_si128((__m128i *)src2); | 
| 1381 |             __m128i uv1 = _mm_unpacklo_epi8(u, v); | 
| 1382 |             __m128i uv2 = _mm_unpackhi_epi8(u, v); | 
| 1383 |             _mm_storeu_si128((__m128i *)dstUV, uv1); | 
| 1384 |             _mm_storeu_si128((__m128i *)(dstUV + 16), uv2); | 
| 1385 |             src1 += 16; | 
| 1386 |             src2 += 16; | 
| 1387 |             dstUV += 32; | 
| 1388 |             x -= 16; | 
| 1389 |         } | 
| 1390 |         while (x--) { | 
| 1391 |             *dstUV++ = *src1++; | 
| 1392 |             *dstUV++ = *src2++; | 
| 1393 |         } | 
| 1394 |         src1 += srcUVPitchLeft; | 
| 1395 |         src2 += srcUVPitchLeft; | 
| 1396 |         dstUV += dstUVPitchLeft; | 
| 1397 |     } | 
| 1398 |  | 
| 1399 |     if (tmp) { | 
| 1400 |         SDL_free(tmp); | 
| 1401 |     } | 
| 1402 |     return true; | 
| 1403 | } | 
| 1404 |  | 
| 1405 | static bool SDL_TARGETING("sse2" ) SDL_ConvertPixels_SplitNV_to_UVPlanes_SSE2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch, bool reverseUV) | 
| 1406 | { | 
| 1407 |     int x, y; | 
| 1408 |     const int UVwidth = (width + 1) / 2; | 
| 1409 |     const int UVheight = (height + 1) / 2; | 
| 1410 |     const int srcUVPitch = ((src_pitch + 1) / 2) * 2; | 
| 1411 |     const int srcUVPitchLeft = srcUVPitch - UVwidth * 2; | 
| 1412 |     const int dstUVPitch = ((dst_pitch + 1) / 2); | 
| 1413 |     const int dstUVPitchLeft = dstUVPitch - UVwidth; | 
| 1414 |     const Uint8 *srcUV; | 
| 1415 |     Uint8 *dst1, *dst2; | 
| 1416 |     Uint8 *tmp = NULL; | 
| 1417 |  | 
| 1418 |     // Skip the Y plane | 
| 1419 |     src = (const Uint8 *)src + height * src_pitch; | 
| 1420 |     dst = (Uint8 *)dst + height * dst_pitch; | 
| 1421 |  | 
| 1422 |     if (src == dst) { | 
| 1423 |         // Need to make a copy of the buffer so we don't clobber it while converting | 
| 1424 |         tmp = (Uint8 *)SDL_malloc((size_t)UVheight * srcUVPitch); | 
| 1425 |         if (tmp == NULL) { | 
| 1426 |             return false; | 
| 1427 |         } | 
| 1428 |         SDL_memcpy(tmp, src, (size_t)UVheight * srcUVPitch); | 
| 1429 |         src = tmp; | 
| 1430 |     } | 
| 1431 |  | 
| 1432 |     if (reverseUV) { | 
| 1433 |         dst2 = (Uint8 *)dst; | 
| 1434 |         dst1 = dst2 + UVheight * dstUVPitch; | 
| 1435 |     } else { | 
| 1436 |         dst1 = (Uint8 *)dst; | 
| 1437 |         dst2 = dst1 + UVheight * dstUVPitch; | 
| 1438 |     } | 
| 1439 |     srcUV = (const Uint8 *)src; | 
| 1440 |  | 
| 1441 |     y = UVheight; | 
| 1442 |     while (y--) { | 
| 1443 |         __m128i mask = _mm_set1_epi16(0x00FF); | 
| 1444 |         x = UVwidth; | 
| 1445 |         while (x >= 16) { | 
| 1446 |             __m128i uv1 = _mm_loadu_si128((__m128i *)srcUV); | 
| 1447 |             __m128i uv2 = _mm_loadu_si128((__m128i *)(srcUV + 16)); | 
| 1448 |             __m128i u1 = _mm_and_si128(uv1, mask); | 
| 1449 |             __m128i u2 = _mm_and_si128(uv2, mask); | 
| 1450 |             __m128i u = _mm_packus_epi16(u1, u2); | 
| 1451 |             __m128i v1 = _mm_srli_epi16(uv1, 8); | 
| 1452 |             __m128i v2 = _mm_srli_epi16(uv2, 8); | 
| 1453 |             __m128i v = _mm_packus_epi16(v1, v2); | 
| 1454 |             _mm_storeu_si128((__m128i *)dst1, u); | 
| 1455 |             _mm_storeu_si128((__m128i *)dst2, v); | 
| 1456 |             srcUV += 32; | 
| 1457 |             dst1 += 16; | 
| 1458 |             dst2 += 16; | 
| 1459 |             x -= 16; | 
| 1460 |         } | 
| 1461 |         while (x--) { | 
| 1462 |             *dst1++ = *srcUV++; | 
| 1463 |             *dst2++ = *srcUV++; | 
| 1464 |         } | 
| 1465 |         srcUV += srcUVPitchLeft; | 
| 1466 |         dst1 += dstUVPitchLeft; | 
| 1467 |         dst2 += dstUVPitchLeft; | 
| 1468 |     } | 
| 1469 |  | 
| 1470 |     if (tmp) { | 
| 1471 |         SDL_free(tmp); | 
| 1472 |     } | 
| 1473 |     return true; | 
| 1474 | } | 
| 1475 |  | 
| 1476 | static bool SDL_TARGETING("sse2" ) SDL_ConvertPixels_SwapNV_SSE2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 1477 | { | 
| 1478 |     int x, y; | 
| 1479 |     const int UVwidth = (width + 1) / 2; | 
| 1480 |     const int UVheight = (height + 1) / 2; | 
| 1481 |     const int srcUVPitch = ((src_pitch + 1) / 2) * 2; | 
| 1482 |     const int srcUVPitchLeft = (srcUVPitch - UVwidth * 2) / sizeof(Uint16); | 
| 1483 |     const int dstUVPitch = ((dst_pitch + 1) / 2) * 2; | 
| 1484 |     const int dstUVPitchLeft = (dstUVPitch - UVwidth * 2) / sizeof(Uint16); | 
| 1485 |     const Uint16 *srcUV; | 
| 1486 |     Uint16 *dstUV; | 
| 1487 |  | 
| 1488 |     // Skip the Y plane | 
| 1489 |     src = (const Uint8 *)src + height * src_pitch; | 
| 1490 |     dst = (Uint8 *)dst + height * dst_pitch; | 
| 1491 |  | 
| 1492 |     srcUV = (const Uint16 *)src; | 
| 1493 |     dstUV = (Uint16 *)dst; | 
| 1494 |     y = UVheight; | 
| 1495 |     while (y--) { | 
| 1496 |         x = UVwidth; | 
| 1497 |         while (x >= 8) { | 
| 1498 |             __m128i uv = _mm_loadu_si128((__m128i *)srcUV); | 
| 1499 |             __m128i v = _mm_slli_epi16(uv, 8); | 
| 1500 |             __m128i u = _mm_srli_epi16(uv, 8); | 
| 1501 |             __m128i vu = _mm_or_si128(v, u); | 
| 1502 |             _mm_storeu_si128((__m128i *)dstUV, vu); | 
| 1503 |             srcUV += 8; | 
| 1504 |             dstUV += 8; | 
| 1505 |             x -= 8; | 
| 1506 |         } | 
| 1507 |         while (x--) { | 
| 1508 |             *dstUV++ = SDL_Swap16(*srcUV++); | 
| 1509 |         } | 
| 1510 |         srcUV += srcUVPitchLeft; | 
| 1511 |         dstUV += dstUVPitchLeft; | 
| 1512 |     } | 
| 1513 |     return true; | 
| 1514 | } | 
| 1515 | #endif | 
| 1516 |  | 
| 1517 | static bool SDL_ConvertPixels_PackUVPlanes_to_NV_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch, bool reverseUV) | 
| 1518 | { | 
| 1519 |     int x, y; | 
| 1520 |     const int UVwidth = (width + 1) / 2; | 
| 1521 |     const int UVheight = (height + 1) / 2; | 
| 1522 |     const int srcUVPitch = ((src_pitch + 1) / 2); | 
| 1523 |     const int srcUVPitchLeft = srcUVPitch - UVwidth; | 
| 1524 |     const int dstUVPitch = ((dst_pitch + 1) / 2) * 2; | 
| 1525 |     const int dstUVPitchLeft = dstUVPitch - UVwidth * 2; | 
| 1526 |     const Uint8 *src1, *src2; | 
| 1527 |     Uint8 *dstUV; | 
| 1528 |     Uint8 *tmp = NULL; | 
| 1529 |  | 
| 1530 |     // Skip the Y plane | 
| 1531 |     src = (const Uint8 *)src + height * src_pitch; | 
| 1532 |     dst = (Uint8 *)dst + height * dst_pitch; | 
| 1533 |  | 
| 1534 |     if (src == dst) { | 
| 1535 |         // Need to make a copy of the buffer so we don't clobber it while converting | 
| 1536 |         tmp = (Uint8 *)SDL_malloc((size_t)2 * UVheight * srcUVPitch); | 
| 1537 |         if (!tmp) { | 
| 1538 |             return false; | 
| 1539 |         } | 
| 1540 |         SDL_memcpy(tmp, src, (size_t)2 * UVheight * srcUVPitch); | 
| 1541 |         src = tmp; | 
| 1542 |     } | 
| 1543 |  | 
| 1544 |     if (reverseUV) { | 
| 1545 |         src2 = (const Uint8 *)src; | 
| 1546 |         src1 = src2 + UVheight * srcUVPitch; | 
| 1547 |     } else { | 
| 1548 |         src1 = (const Uint8 *)src; | 
| 1549 |         src2 = src1 + UVheight * srcUVPitch; | 
| 1550 |     } | 
| 1551 |     dstUV = (Uint8 *)dst; | 
| 1552 |  | 
| 1553 |     y = UVheight; | 
| 1554 |     while (y--) { | 
| 1555 |         x = UVwidth; | 
| 1556 |         while (x--) { | 
| 1557 |             *dstUV++ = *src1++; | 
| 1558 |             *dstUV++ = *src2++; | 
| 1559 |         } | 
| 1560 |         src1 += srcUVPitchLeft; | 
| 1561 |         src2 += srcUVPitchLeft; | 
| 1562 |         dstUV += dstUVPitchLeft; | 
| 1563 |     } | 
| 1564 |  | 
| 1565 |     if (tmp) { | 
| 1566 |         SDL_free(tmp); | 
| 1567 |     } | 
| 1568 |     return true; | 
| 1569 | } | 
| 1570 |  | 
| 1571 | static bool SDL_ConvertPixels_SplitNV_to_UVPlanes_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch, bool reverseUV) | 
| 1572 | { | 
| 1573 |     int x, y; | 
| 1574 |     const int UVwidth = (width + 1) / 2; | 
| 1575 |     const int UVheight = (height + 1) / 2; | 
| 1576 |     const int srcUVPitch = ((src_pitch + 1) / 2) * 2; | 
| 1577 |     const int srcUVPitchLeft = srcUVPitch - UVwidth * 2; | 
| 1578 |     const int dstUVPitch = ((dst_pitch + 1) / 2); | 
| 1579 |     const int dstUVPitchLeft = dstUVPitch - UVwidth; | 
| 1580 |     const Uint8 *srcUV; | 
| 1581 |     Uint8 *dst1, *dst2; | 
| 1582 |     Uint8 *tmp = NULL; | 
| 1583 |  | 
| 1584 |     // Skip the Y plane | 
| 1585 |     src = (const Uint8 *)src + height * src_pitch; | 
| 1586 |     dst = (Uint8 *)dst + height * dst_pitch; | 
| 1587 |  | 
| 1588 |     if (src == dst) { | 
| 1589 |         // Need to make a copy of the buffer so we don't clobber it while converting | 
| 1590 |         tmp = (Uint8 *)SDL_malloc((size_t)UVheight * srcUVPitch); | 
| 1591 |         if (!tmp) { | 
| 1592 |             return false; | 
| 1593 |         } | 
| 1594 |         SDL_memcpy(tmp, src, (size_t)UVheight * srcUVPitch); | 
| 1595 |         src = tmp; | 
| 1596 |     } | 
| 1597 |  | 
| 1598 |     if (reverseUV) { | 
| 1599 |         dst2 = (Uint8 *)dst; | 
| 1600 |         dst1 = dst2 + UVheight * dstUVPitch; | 
| 1601 |     } else { | 
| 1602 |         dst1 = (Uint8 *)dst; | 
| 1603 |         dst2 = dst1 + UVheight * dstUVPitch; | 
| 1604 |     } | 
| 1605 |     srcUV = (const Uint8 *)src; | 
| 1606 |  | 
| 1607 |     y = UVheight; | 
| 1608 |     while (y--) { | 
| 1609 |         x = UVwidth; | 
| 1610 |         while (x--) { | 
| 1611 |             *dst1++ = *srcUV++; | 
| 1612 |             *dst2++ = *srcUV++; | 
| 1613 |         } | 
| 1614 |         srcUV += srcUVPitchLeft; | 
| 1615 |         dst1 += dstUVPitchLeft; | 
| 1616 |         dst2 += dstUVPitchLeft; | 
| 1617 |     } | 
| 1618 |  | 
| 1619 |     if (tmp) { | 
| 1620 |         SDL_free(tmp); | 
| 1621 |     } | 
| 1622 |     return true; | 
| 1623 | } | 
| 1624 |  | 
| 1625 | static bool SDL_ConvertPixels_SwapNV_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 1626 | { | 
| 1627 |     int x, y; | 
| 1628 |     const int UVwidth = (width + 1) / 2; | 
| 1629 |     const int UVheight = (height + 1) / 2; | 
| 1630 |     const int srcUVPitch = ((src_pitch + 1) / 2) * 2; | 
| 1631 |     const int dstUVPitch = ((dst_pitch + 1) / 2) * 2; | 
| 1632 |  | 
| 1633 |     // Skip the Y plane | 
| 1634 |     src = (const Uint8 *)src + height * src_pitch; | 
| 1635 |     dst = (Uint8 *)dst + height * dst_pitch; | 
| 1636 |  | 
| 1637 |     bool aligned = (((uintptr_t)src | (uintptr_t)dst) & 1) == 0; | 
| 1638 |     if (aligned) { | 
| 1639 |         const int srcUVPitchLeft = (srcUVPitch - UVwidth * 2) / sizeof(Uint16); | 
| 1640 |         const int dstUVPitchLeft = (dstUVPitch - UVwidth * 2) / sizeof(Uint16); | 
| 1641 |         const Uint16 *srcUV = (const Uint16 *)src; | 
| 1642 |         Uint16 *dstUV = (Uint16 *)dst; | 
| 1643 |         y = UVheight; | 
| 1644 |         while (y--) { | 
| 1645 |             x = UVwidth; | 
| 1646 |             while (x--) { | 
| 1647 |                 *dstUV++ = SDL_Swap16(*srcUV++); | 
| 1648 |             } | 
| 1649 |             srcUV += srcUVPitchLeft; | 
| 1650 |             dstUV += dstUVPitchLeft; | 
| 1651 |         } | 
| 1652 |     } else { | 
| 1653 |         const int srcUVPitchLeft = (srcUVPitch - UVwidth * 2); | 
| 1654 |         const int dstUVPitchLeft = (dstUVPitch - UVwidth * 2); | 
| 1655 |         const Uint8 *srcUV = (const Uint8 *)src; | 
| 1656 |         Uint8 *dstUV = (Uint8 *)dst; | 
| 1657 |         y = UVheight; | 
| 1658 |         while (y--) { | 
| 1659 |             x = UVwidth; | 
| 1660 |             while (x--) { | 
| 1661 |                 Uint8 u = *srcUV++; | 
| 1662 |                 Uint8 v = *srcUV++; | 
| 1663 |                 *dstUV++ = v; | 
| 1664 |                 *dstUV++ = u; | 
| 1665 |             } | 
| 1666 |             srcUV += srcUVPitchLeft; | 
| 1667 |             dstUV += dstUVPitchLeft; | 
| 1668 |         } | 
| 1669 |     } | 
| 1670 |     return true; | 
| 1671 | } | 
| 1672 |  | 
| 1673 | static bool SDL_ConvertPixels_PackUVPlanes_to_NV(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch, bool reverseUV) | 
| 1674 | { | 
| 1675 | #ifdef SDL_SSE2_INTRINSICS | 
| 1676 |     if (SDL_HasSSE2()) { | 
| 1677 |       return SDL_ConvertPixels_PackUVPlanes_to_NV_SSE2(width, height, src, src_pitch, dst, dst_pitch, reverseUV); | 
| 1678 |     } | 
| 1679 | #endif | 
| 1680 |     return SDL_ConvertPixels_PackUVPlanes_to_NV_std(width, height, src, src_pitch, dst, dst_pitch, reverseUV); | 
| 1681 | } | 
| 1682 |  | 
| 1683 | static bool SDL_ConvertPixels_SplitNV_to_UVPlanes(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch, bool reverseUV) | 
| 1684 | { | 
| 1685 | #ifdef SDL_SSE2_INTRINSICS | 
| 1686 |     if (SDL_HasSSE2()) { | 
| 1687 |       return SDL_ConvertPixels_SplitNV_to_UVPlanes_SSE2(width, height, src, src_pitch, dst, dst_pitch, reverseUV); | 
| 1688 |     } | 
| 1689 | #endif | 
| 1690 |     return SDL_ConvertPixels_SplitNV_to_UVPlanes_std(width, height, src, src_pitch, dst, dst_pitch, reverseUV); | 
| 1691 | } | 
| 1692 |  | 
| 1693 | static bool SDL_ConvertPixels_SwapNV(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 1694 | { | 
| 1695 | #ifdef SDL_SSE2_INTRINSICS | 
| 1696 |     if (SDL_HasSSE2()) { | 
| 1697 |       return SDL_ConvertPixels_SwapNV_SSE2(width, height, src, src_pitch, dst, dst_pitch); | 
| 1698 |     } | 
| 1699 | #endif | 
| 1700 |     return SDL_ConvertPixels_SwapNV_std(width, height, src, src_pitch, dst, dst_pitch); | 
| 1701 | } | 
| 1702 |  | 
| 1703 | static bool SDL_ConvertPixels_Planar2x2_to_Planar2x2(int width, int height, | 
| 1704 |                                                      SDL_PixelFormat src_format, const void *src, int src_pitch, | 
| 1705 |                                                      SDL_PixelFormat dst_format, void *dst, int dst_pitch) | 
| 1706 | { | 
| 1707 |     if (src != dst) { | 
| 1708 |         // Copy Y plane | 
| 1709 |         int i; | 
| 1710 |         const Uint8 *srcY = (const Uint8 *)src; | 
| 1711 |         Uint8 *dstY = (Uint8 *)dst; | 
| 1712 |         for (i = height; i--;) { | 
| 1713 |             SDL_memcpy(dstY, srcY, width); | 
| 1714 |             srcY += src_pitch; | 
| 1715 |             dstY += dst_pitch; | 
| 1716 |         } | 
| 1717 |     } | 
| 1718 |  | 
| 1719 |     switch (src_format) { | 
| 1720 |     case SDL_PIXELFORMAT_YV12: | 
| 1721 |         switch (dst_format) { | 
| 1722 |         case SDL_PIXELFORMAT_IYUV: | 
| 1723 |             return SDL_ConvertPixels_SwapUVPlanes(width, height, src, src_pitch, dst, dst_pitch); | 
| 1724 |         case SDL_PIXELFORMAT_NV12: | 
| 1725 |             return SDL_ConvertPixels_PackUVPlanes_to_NV(width, height, src, src_pitch, dst, dst_pitch, true); | 
| 1726 |         case SDL_PIXELFORMAT_NV21: | 
| 1727 |             return SDL_ConvertPixels_PackUVPlanes_to_NV(width, height, src, src_pitch, dst, dst_pitch, false); | 
| 1728 |         default: | 
| 1729 |             break; | 
| 1730 |         } | 
| 1731 |         break; | 
| 1732 |     case SDL_PIXELFORMAT_IYUV: | 
| 1733 |         switch (dst_format) { | 
| 1734 |         case SDL_PIXELFORMAT_YV12: | 
| 1735 |             return SDL_ConvertPixels_SwapUVPlanes(width, height, src, src_pitch, dst, dst_pitch); | 
| 1736 |         case SDL_PIXELFORMAT_NV12: | 
| 1737 |             return SDL_ConvertPixels_PackUVPlanes_to_NV(width, height, src, src_pitch, dst, dst_pitch, false); | 
| 1738 |         case SDL_PIXELFORMAT_NV21: | 
| 1739 |             return SDL_ConvertPixels_PackUVPlanes_to_NV(width, height, src, src_pitch, dst, dst_pitch, true); | 
| 1740 |         default: | 
| 1741 |             break; | 
| 1742 |         } | 
| 1743 |         break; | 
| 1744 |     case SDL_PIXELFORMAT_NV12: | 
| 1745 |         switch (dst_format) { | 
| 1746 |         case SDL_PIXELFORMAT_YV12: | 
| 1747 |             return SDL_ConvertPixels_SplitNV_to_UVPlanes(width, height, src, src_pitch, dst, dst_pitch, true); | 
| 1748 |         case SDL_PIXELFORMAT_IYUV: | 
| 1749 |             return SDL_ConvertPixels_SplitNV_to_UVPlanes(width, height, src, src_pitch, dst, dst_pitch, false); | 
| 1750 |         case SDL_PIXELFORMAT_NV21: | 
| 1751 |             return SDL_ConvertPixels_SwapNV(width, height, src, src_pitch, dst, dst_pitch); | 
| 1752 |         default: | 
| 1753 |             break; | 
| 1754 |         } | 
| 1755 |         break; | 
| 1756 |     case SDL_PIXELFORMAT_NV21: | 
| 1757 |         switch (dst_format) { | 
| 1758 |         case SDL_PIXELFORMAT_YV12: | 
| 1759 |             return SDL_ConvertPixels_SplitNV_to_UVPlanes(width, height, src, src_pitch, dst, dst_pitch, false); | 
| 1760 |         case SDL_PIXELFORMAT_IYUV: | 
| 1761 |             return SDL_ConvertPixels_SplitNV_to_UVPlanes(width, height, src, src_pitch, dst, dst_pitch, true); | 
| 1762 |         case SDL_PIXELFORMAT_NV12: | 
| 1763 |             return SDL_ConvertPixels_SwapNV(width, height, src, src_pitch, dst, dst_pitch); | 
| 1764 |         default: | 
| 1765 |             break; | 
| 1766 |         } | 
| 1767 |         break; | 
| 1768 |     default: | 
| 1769 |         break; | 
| 1770 |     } | 
| 1771 |     return SDL_SetError("SDL_ConvertPixels_Planar2x2_to_Planar2x2: Unsupported YUV conversion: %s -> %s" , SDL_GetPixelFormatName(src_format), | 
| 1772 |                         SDL_GetPixelFormatName(dst_format)); | 
| 1773 | } | 
| 1774 |  | 
| 1775 | #ifdef SDL_SSE2_INTRINSICS | 
| 1776 | #define PACKED4_TO_PACKED4_ROW_SSE2(shuffle)                      \ | 
| 1777 |     while (x >= 4) {                                              \ | 
| 1778 |         __m128i yuv = _mm_loadu_si128((__m128i *)srcYUV);         \ | 
| 1779 |         __m128i lo = _mm_unpacklo_epi8(yuv, _mm_setzero_si128()); \ | 
| 1780 |         __m128i hi = _mm_unpackhi_epi8(yuv, _mm_setzero_si128()); \ | 
| 1781 |         lo = _mm_shufflelo_epi16(lo, shuffle);                    \ | 
| 1782 |         lo = _mm_shufflehi_epi16(lo, shuffle);                    \ | 
| 1783 |         hi = _mm_shufflelo_epi16(hi, shuffle);                    \ | 
| 1784 |         hi = _mm_shufflehi_epi16(hi, shuffle);                    \ | 
| 1785 |         yuv = _mm_packus_epi16(lo, hi);                           \ | 
| 1786 |         _mm_storeu_si128((__m128i *)dstYUV, yuv);                 \ | 
| 1787 |         srcYUV += 16;                                             \ | 
| 1788 |         dstYUV += 16;                                             \ | 
| 1789 |         x -= 4;                                                   \ | 
| 1790 |     } | 
| 1791 |  | 
| 1792 | static bool SDL_TARGETING("sse2" ) SDL_ConvertPixels_YUY2_to_UYVY_SSE2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 1793 | { | 
| 1794 |     int x, y; | 
| 1795 |     const int YUVwidth = (width + 1) / 2; | 
| 1796 |     const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); | 
| 1797 |     const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); | 
| 1798 |     const Uint8 *srcYUV = (const Uint8 *)src; | 
| 1799 |     Uint8 *dstYUV = (Uint8 *)dst; | 
| 1800 |  | 
| 1801 |     y = height; | 
| 1802 |     x = YUVwidth; | 
| 1803 |     while (y--) { | 
| 1804 |         PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(2, 3, 0, 1)); | 
| 1805 |         while (x--) { | 
| 1806 |             Uint8 Y1, U, Y2, V; | 
| 1807 |  | 
| 1808 |             Y1 = srcYUV[0]; | 
| 1809 |             U = srcYUV[1]; | 
| 1810 |             Y2 = srcYUV[2]; | 
| 1811 |             V = srcYUV[3]; | 
| 1812 |             srcYUV += 4; | 
| 1813 |  | 
| 1814 |             dstYUV[0] = U; | 
| 1815 |             dstYUV[1] = Y1; | 
| 1816 |             dstYUV[2] = V; | 
| 1817 |             dstYUV[3] = Y2; | 
| 1818 |             dstYUV += 4; | 
| 1819 |         } | 
| 1820 |         srcYUV += srcYUVPitchLeft; | 
| 1821 |         dstYUV += dstYUVPitchLeft; | 
| 1822 |         x = YUVwidth; | 
| 1823 |     } | 
| 1824 |     return true; | 
| 1825 | } | 
| 1826 |  | 
| 1827 | static bool SDL_TARGETING("sse2" ) SDL_ConvertPixels_YUY2_to_YVYU_SSE2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 1828 | { | 
| 1829 |     int x, y; | 
| 1830 |     const int YUVwidth = (width + 1) / 2; | 
| 1831 |     const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); | 
| 1832 |     const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); | 
| 1833 |     const Uint8 *srcYUV = (const Uint8 *)src; | 
| 1834 |     Uint8 *dstYUV = (Uint8 *)dst; | 
| 1835 |  | 
| 1836 |     y = height; | 
| 1837 |     x = YUVwidth; | 
| 1838 |     while (y--) { | 
| 1839 |         PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(1, 2, 3, 0)); | 
| 1840 |         while (x--) { | 
| 1841 |             Uint8 Y1, U, Y2, V; | 
| 1842 |  | 
| 1843 |             Y1 = srcYUV[0]; | 
| 1844 |             U = srcYUV[1]; | 
| 1845 |             Y2 = srcYUV[2]; | 
| 1846 |             V = srcYUV[3]; | 
| 1847 |             srcYUV += 4; | 
| 1848 |  | 
| 1849 |             dstYUV[0] = Y1; | 
| 1850 |             dstYUV[1] = V; | 
| 1851 |             dstYUV[2] = Y2; | 
| 1852 |             dstYUV[3] = U; | 
| 1853 |             dstYUV += 4; | 
| 1854 |         } | 
| 1855 |         srcYUV += srcYUVPitchLeft; | 
| 1856 |         dstYUV += dstYUVPitchLeft; | 
| 1857 |         x = YUVwidth; | 
| 1858 |     } | 
| 1859 |     return true; | 
| 1860 | } | 
| 1861 |  | 
| 1862 | static bool SDL_TARGETING("sse2" ) SDL_ConvertPixels_UYVY_to_YUY2_SSE2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 1863 | { | 
| 1864 |     int x, y; | 
| 1865 |     const int YUVwidth = (width + 1) / 2; | 
| 1866 |     const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); | 
| 1867 |     const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); | 
| 1868 |     const Uint8 *srcYUV = (const Uint8 *)src; | 
| 1869 |     Uint8 *dstYUV = (Uint8 *)dst; | 
| 1870 |  | 
| 1871 |     y = height; | 
| 1872 |     x = YUVwidth; | 
| 1873 |     while (y--) { | 
| 1874 |         PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(2, 3, 0, 1)); | 
| 1875 |         while (x--) { | 
| 1876 |             Uint8 Y1, U, Y2, V; | 
| 1877 |  | 
| 1878 |             U = srcYUV[0]; | 
| 1879 |             Y1 = srcYUV[1]; | 
| 1880 |             V = srcYUV[2]; | 
| 1881 |             Y2 = srcYUV[3]; | 
| 1882 |             srcYUV += 4; | 
| 1883 |  | 
| 1884 |             dstYUV[0] = Y1; | 
| 1885 |             dstYUV[1] = U; | 
| 1886 |             dstYUV[2] = Y2; | 
| 1887 |             dstYUV[3] = V; | 
| 1888 |             dstYUV += 4; | 
| 1889 |         } | 
| 1890 |         srcYUV += srcYUVPitchLeft; | 
| 1891 |         dstYUV += dstYUVPitchLeft; | 
| 1892 |         x = YUVwidth; | 
| 1893 |     } | 
| 1894 |     return true; | 
| 1895 | } | 
| 1896 |  | 
| 1897 | static bool SDL_TARGETING("sse2" ) SDL_ConvertPixels_UYVY_to_YVYU_SSE2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 1898 | { | 
| 1899 |     int x, y; | 
| 1900 |     const int YUVwidth = (width + 1) / 2; | 
| 1901 |     const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); | 
| 1902 |     const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); | 
| 1903 |     const Uint8 *srcYUV = (const Uint8 *)src; | 
| 1904 |     Uint8 *dstYUV = (Uint8 *)dst; | 
| 1905 |  | 
| 1906 |     y = height; | 
| 1907 |     x = YUVwidth; | 
| 1908 |     while (y--) { | 
| 1909 |         PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(0, 3, 2, 1)); | 
| 1910 |         while (x--) { | 
| 1911 |             Uint8 Y1, U, Y2, V; | 
| 1912 |  | 
| 1913 |             U = srcYUV[0]; | 
| 1914 |             Y1 = srcYUV[1]; | 
| 1915 |             V = srcYUV[2]; | 
| 1916 |             Y2 = srcYUV[3]; | 
| 1917 |             srcYUV += 4; | 
| 1918 |  | 
| 1919 |             dstYUV[0] = Y1; | 
| 1920 |             dstYUV[1] = V; | 
| 1921 |             dstYUV[2] = Y2; | 
| 1922 |             dstYUV[3] = U; | 
| 1923 |             dstYUV += 4; | 
| 1924 |         } | 
| 1925 |         srcYUV += srcYUVPitchLeft; | 
| 1926 |         dstYUV += dstYUVPitchLeft; | 
| 1927 |         x = YUVwidth; | 
| 1928 |     } | 
| 1929 |     return true; | 
| 1930 | } | 
| 1931 |  | 
| 1932 | static bool SDL_TARGETING("sse2" ) SDL_ConvertPixels_YVYU_to_YUY2_SSE2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 1933 | { | 
| 1934 |     int x, y; | 
| 1935 |     const int YUVwidth = (width + 1) / 2; | 
| 1936 |     const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); | 
| 1937 |     const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); | 
| 1938 |     const Uint8 *srcYUV = (const Uint8 *)src; | 
| 1939 |     Uint8 *dstYUV = (Uint8 *)dst; | 
| 1940 |  | 
| 1941 |     y = height; | 
| 1942 |     x = YUVwidth; | 
| 1943 |     while (y--) { | 
| 1944 |         PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(1, 2, 3, 0)); | 
| 1945 |         while (x--) { | 
| 1946 |             Uint8 Y1, U, Y2, V; | 
| 1947 |  | 
| 1948 |             Y1 = srcYUV[0]; | 
| 1949 |             V = srcYUV[1]; | 
| 1950 |             Y2 = srcYUV[2]; | 
| 1951 |             U = srcYUV[3]; | 
| 1952 |             srcYUV += 4; | 
| 1953 |  | 
| 1954 |             dstYUV[0] = Y1; | 
| 1955 |             dstYUV[1] = U; | 
| 1956 |             dstYUV[2] = Y2; | 
| 1957 |             dstYUV[3] = V; | 
| 1958 |             dstYUV += 4; | 
| 1959 |         } | 
| 1960 |         srcYUV += srcYUVPitchLeft; | 
| 1961 |         dstYUV += dstYUVPitchLeft; | 
| 1962 |         x = YUVwidth; | 
| 1963 |     } | 
| 1964 |     return true; | 
| 1965 | } | 
| 1966 |  | 
| 1967 | static bool SDL_TARGETING("sse2" ) SDL_ConvertPixels_YVYU_to_UYVY_SSE2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 1968 | { | 
| 1969 |     int x, y; | 
| 1970 |     const int YUVwidth = (width + 1) / 2; | 
| 1971 |     const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); | 
| 1972 |     const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); | 
| 1973 |     const Uint8 *srcYUV = (const Uint8 *)src; | 
| 1974 |     Uint8 *dstYUV = (Uint8 *)dst; | 
| 1975 |  | 
| 1976 |     y = height; | 
| 1977 |     x = YUVwidth; | 
| 1978 |     while (y--) { | 
| 1979 |         PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(2, 1, 0, 3)); | 
| 1980 |         while (x--) { | 
| 1981 |             Uint8 Y1, U, Y2, V; | 
| 1982 |  | 
| 1983 |             Y1 = srcYUV[0]; | 
| 1984 |             V = srcYUV[1]; | 
| 1985 |             Y2 = srcYUV[2]; | 
| 1986 |             U = srcYUV[3]; | 
| 1987 |             srcYUV += 4; | 
| 1988 |  | 
| 1989 |             dstYUV[0] = U; | 
| 1990 |             dstYUV[1] = Y1; | 
| 1991 |             dstYUV[2] = V; | 
| 1992 |             dstYUV[3] = Y2; | 
| 1993 |             dstYUV += 4; | 
| 1994 |         } | 
| 1995 |         srcYUV += srcYUVPitchLeft; | 
| 1996 |         dstYUV += dstYUVPitchLeft; | 
| 1997 |         x = YUVwidth; | 
| 1998 |     } | 
| 1999 |     return true; | 
| 2000 | } | 
| 2001 | #endif | 
| 2002 |  | 
| 2003 | static bool SDL_ConvertPixels_YUY2_to_UYVY_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 2004 | { | 
| 2005 |     int x, y; | 
| 2006 |     const int YUVwidth = (width + 1) / 2; | 
| 2007 |     const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); | 
| 2008 |     const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); | 
| 2009 |     const Uint8 *srcYUV = (const Uint8 *)src; | 
| 2010 |     Uint8 *dstYUV = (Uint8 *)dst; | 
| 2011 |  | 
| 2012 |     y = height; | 
| 2013 |     while (y--) { | 
| 2014 |         x = YUVwidth; | 
| 2015 |         while (x--) { | 
| 2016 |             Uint8 Y1, U, Y2, V; | 
| 2017 |  | 
| 2018 |             Y1 = srcYUV[0]; | 
| 2019 |             U = srcYUV[1]; | 
| 2020 |             Y2 = srcYUV[2]; | 
| 2021 |             V = srcYUV[3]; | 
| 2022 |             srcYUV += 4; | 
| 2023 |  | 
| 2024 |             dstYUV[0] = U; | 
| 2025 |             dstYUV[1] = Y1; | 
| 2026 |             dstYUV[2] = V; | 
| 2027 |             dstYUV[3] = Y2; | 
| 2028 |             dstYUV += 4; | 
| 2029 |         } | 
| 2030 |         srcYUV += srcYUVPitchLeft; | 
| 2031 |         dstYUV += dstYUVPitchLeft; | 
| 2032 |     } | 
| 2033 |     return true; | 
| 2034 | } | 
| 2035 |  | 
| 2036 | static bool SDL_ConvertPixels_YUY2_to_YVYU_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 2037 | { | 
| 2038 |     int x, y; | 
| 2039 |     const int YUVwidth = (width + 1) / 2; | 
| 2040 |     const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); | 
| 2041 |     const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); | 
| 2042 |     const Uint8 *srcYUV = (const Uint8 *)src; | 
| 2043 |     Uint8 *dstYUV = (Uint8 *)dst; | 
| 2044 |  | 
| 2045 |     y = height; | 
| 2046 |     while (y--) { | 
| 2047 |         x = YUVwidth; | 
| 2048 |         while (x--) { | 
| 2049 |             Uint8 Y1, U, Y2, V; | 
| 2050 |  | 
| 2051 |             Y1 = srcYUV[0]; | 
| 2052 |             U = srcYUV[1]; | 
| 2053 |             Y2 = srcYUV[2]; | 
| 2054 |             V = srcYUV[3]; | 
| 2055 |             srcYUV += 4; | 
| 2056 |  | 
| 2057 |             dstYUV[0] = Y1; | 
| 2058 |             dstYUV[1] = V; | 
| 2059 |             dstYUV[2] = Y2; | 
| 2060 |             dstYUV[3] = U; | 
| 2061 |             dstYUV += 4; | 
| 2062 |         } | 
| 2063 |         srcYUV += srcYUVPitchLeft; | 
| 2064 |         dstYUV += dstYUVPitchLeft; | 
| 2065 |     } | 
| 2066 |     return true; | 
| 2067 | } | 
| 2068 |  | 
| 2069 | static bool SDL_ConvertPixels_UYVY_to_YUY2_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 2070 | { | 
| 2071 |     int x, y; | 
| 2072 |     const int YUVwidth = (width + 1) / 2; | 
| 2073 |     const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); | 
| 2074 |     const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); | 
| 2075 |     const Uint8 *srcYUV = (const Uint8 *)src; | 
| 2076 |     Uint8 *dstYUV = (Uint8 *)dst; | 
| 2077 |  | 
| 2078 |     y = height; | 
| 2079 |     while (y--) { | 
| 2080 |         x = YUVwidth; | 
| 2081 |         while (x--) { | 
| 2082 |             Uint8 Y1, U, Y2, V; | 
| 2083 |  | 
| 2084 |             U = srcYUV[0]; | 
| 2085 |             Y1 = srcYUV[1]; | 
| 2086 |             V = srcYUV[2]; | 
| 2087 |             Y2 = srcYUV[3]; | 
| 2088 |             srcYUV += 4; | 
| 2089 |  | 
| 2090 |             dstYUV[0] = Y1; | 
| 2091 |             dstYUV[1] = U; | 
| 2092 |             dstYUV[2] = Y2; | 
| 2093 |             dstYUV[3] = V; | 
| 2094 |             dstYUV += 4; | 
| 2095 |         } | 
| 2096 |         srcYUV += srcYUVPitchLeft; | 
| 2097 |         dstYUV += dstYUVPitchLeft; | 
| 2098 |     } | 
| 2099 |     return true; | 
| 2100 | } | 
| 2101 |  | 
| 2102 | static bool SDL_ConvertPixels_UYVY_to_YVYU_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 2103 | { | 
| 2104 |     int x, y; | 
| 2105 |     const int YUVwidth = (width + 1) / 2; | 
| 2106 |     const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); | 
| 2107 |     const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); | 
| 2108 |     const Uint8 *srcYUV = (const Uint8 *)src; | 
| 2109 |     Uint8 *dstYUV = (Uint8 *)dst; | 
| 2110 |  | 
| 2111 |     y = height; | 
| 2112 |     while (y--) { | 
| 2113 |         x = YUVwidth; | 
| 2114 |         while (x--) { | 
| 2115 |             Uint8 Y1, U, Y2, V; | 
| 2116 |  | 
| 2117 |             U = srcYUV[0]; | 
| 2118 |             Y1 = srcYUV[1]; | 
| 2119 |             V = srcYUV[2]; | 
| 2120 |             Y2 = srcYUV[3]; | 
| 2121 |             srcYUV += 4; | 
| 2122 |  | 
| 2123 |             dstYUV[0] = Y1; | 
| 2124 |             dstYUV[1] = V; | 
| 2125 |             dstYUV[2] = Y2; | 
| 2126 |             dstYUV[3] = U; | 
| 2127 |             dstYUV += 4; | 
| 2128 |         } | 
| 2129 |         srcYUV += srcYUVPitchLeft; | 
| 2130 |         dstYUV += dstYUVPitchLeft; | 
| 2131 |     } | 
| 2132 |     return true; | 
| 2133 | } | 
| 2134 |  | 
| 2135 | static bool SDL_ConvertPixels_YVYU_to_YUY2_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 2136 | { | 
| 2137 |     int x, y; | 
| 2138 |     const int YUVwidth = (width + 1) / 2; | 
| 2139 |     const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); | 
| 2140 |     const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); | 
| 2141 |     const Uint8 *srcYUV = (const Uint8 *)src; | 
| 2142 |     Uint8 *dstYUV = (Uint8 *)dst; | 
| 2143 |  | 
| 2144 |     y = height; | 
| 2145 |     while (y--) { | 
| 2146 |         x = YUVwidth; | 
| 2147 |         while (x--) { | 
| 2148 |             Uint8 Y1, U, Y2, V; | 
| 2149 |  | 
| 2150 |             Y1 = srcYUV[0]; | 
| 2151 |             V = srcYUV[1]; | 
| 2152 |             Y2 = srcYUV[2]; | 
| 2153 |             U = srcYUV[3]; | 
| 2154 |             srcYUV += 4; | 
| 2155 |  | 
| 2156 |             dstYUV[0] = Y1; | 
| 2157 |             dstYUV[1] = U; | 
| 2158 |             dstYUV[2] = Y2; | 
| 2159 |             dstYUV[3] = V; | 
| 2160 |             dstYUV += 4; | 
| 2161 |         } | 
| 2162 |         srcYUV += srcYUVPitchLeft; | 
| 2163 |         dstYUV += dstYUVPitchLeft; | 
| 2164 |     } | 
| 2165 |     return true; | 
| 2166 | } | 
| 2167 |  | 
| 2168 | static bool SDL_ConvertPixels_YVYU_to_UYVY_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 2169 | { | 
| 2170 |     int x, y; | 
| 2171 |     const int YUVwidth = (width + 1) / 2; | 
| 2172 |     const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); | 
| 2173 |     const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); | 
| 2174 |     const Uint8 *srcYUV = (const Uint8 *)src; | 
| 2175 |     Uint8 *dstYUV = (Uint8 *)dst; | 
| 2176 |  | 
| 2177 |     y = height; | 
| 2178 |     while (y--) { | 
| 2179 |         x = YUVwidth; | 
| 2180 |         while (x--) { | 
| 2181 |             Uint8 Y1, U, Y2, V; | 
| 2182 |  | 
| 2183 |             Y1 = srcYUV[0]; | 
| 2184 |             V = srcYUV[1]; | 
| 2185 |             Y2 = srcYUV[2]; | 
| 2186 |             U = srcYUV[3]; | 
| 2187 |             srcYUV += 4; | 
| 2188 |  | 
| 2189 |             dstYUV[0] = U; | 
| 2190 |             dstYUV[1] = Y1; | 
| 2191 |             dstYUV[2] = V; | 
| 2192 |             dstYUV[3] = Y2; | 
| 2193 |             dstYUV += 4; | 
| 2194 |         } | 
| 2195 |         srcYUV += srcYUVPitchLeft; | 
| 2196 |         dstYUV += dstYUVPitchLeft; | 
| 2197 |     } | 
| 2198 |     return true; | 
| 2199 | } | 
| 2200 |  | 
| 2201 | static bool SDL_ConvertPixels_YUY2_to_UYVY(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 2202 | { | 
| 2203 | #ifdef SDL_SSE2_INTRINSICS | 
| 2204 |     if (SDL_HasSSE2()) { | 
| 2205 |       return SDL_ConvertPixels_YUY2_to_UYVY_SSE2(width, height, src, src_pitch, dst, dst_pitch); | 
| 2206 |     } | 
| 2207 | #endif | 
| 2208 |     return SDL_ConvertPixels_YUY2_to_UYVY_std(width, height, src, src_pitch, dst, dst_pitch); | 
| 2209 | } | 
| 2210 |  | 
| 2211 | static bool SDL_ConvertPixels_YUY2_to_YVYU(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 2212 | { | 
| 2213 | #ifdef SDL_SSE2_INTRINSICS | 
| 2214 |     if (SDL_HasSSE2()) { | 
| 2215 |       return SDL_ConvertPixels_YUY2_to_YVYU_SSE2(width, height, src, src_pitch, dst, dst_pitch); | 
| 2216 |     } | 
| 2217 | #endif | 
| 2218 |     return SDL_ConvertPixels_YUY2_to_YVYU_std(width, height, src, src_pitch, dst, dst_pitch); | 
| 2219 | } | 
| 2220 |  | 
| 2221 | static bool SDL_ConvertPixels_UYVY_to_YUY2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 2222 | { | 
| 2223 | #ifdef SDL_SSE2_INTRINSICS | 
| 2224 |     if (SDL_HasSSE2()) { | 
| 2225 |       return SDL_ConvertPixels_UYVY_to_YUY2_SSE2(width, height, src, src_pitch, dst, dst_pitch); | 
| 2226 |     } | 
| 2227 | #endif | 
| 2228 |     return SDL_ConvertPixels_UYVY_to_YUY2_std(width, height, src, src_pitch, dst, dst_pitch); | 
| 2229 | } | 
| 2230 |  | 
| 2231 | static bool SDL_ConvertPixels_UYVY_to_YVYU(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 2232 | { | 
| 2233 | #ifdef SDL_SSE2_INTRINSICS | 
| 2234 |     if (SDL_HasSSE2()) { | 
| 2235 |       return SDL_ConvertPixels_UYVY_to_YVYU_SSE2(width, height, src, src_pitch, dst, dst_pitch); | 
| 2236 |     } | 
| 2237 | #endif | 
| 2238 |     return SDL_ConvertPixels_UYVY_to_YVYU_std(width, height, src, src_pitch, dst, dst_pitch); | 
| 2239 | } | 
| 2240 |  | 
| 2241 | static bool SDL_ConvertPixels_YVYU_to_YUY2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 2242 | { | 
| 2243 | #ifdef SDL_SSE2_INTRINSICS | 
| 2244 |     if (SDL_HasSSE2()) { | 
| 2245 |       return SDL_ConvertPixels_YVYU_to_YUY2_SSE2(width, height, src, src_pitch, dst, dst_pitch); | 
| 2246 |     } | 
| 2247 | #endif | 
| 2248 |     return SDL_ConvertPixels_YVYU_to_YUY2_std(width, height, src, src_pitch, dst, dst_pitch); | 
| 2249 | } | 
| 2250 |  | 
| 2251 | static bool SDL_ConvertPixels_YVYU_to_UYVY(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) | 
| 2252 | { | 
| 2253 | #ifdef SDL_SSE2_INTRINSICS | 
| 2254 |     if (SDL_HasSSE2()) { | 
| 2255 |       return SDL_ConvertPixels_YVYU_to_UYVY_SSE2(width, height, src, src_pitch, dst, dst_pitch); | 
| 2256 |     } | 
| 2257 | #endif | 
| 2258 |     return SDL_ConvertPixels_YVYU_to_UYVY_std(width, height, src, src_pitch, dst, dst_pitch); | 
| 2259 | } | 
| 2260 |  | 
| 2261 | static bool SDL_ConvertPixels_Packed4_to_Packed4(int width, int height, | 
| 2262 |                                                 SDL_PixelFormat src_format, const void *src, int src_pitch, | 
| 2263 |                                                 SDL_PixelFormat dst_format, void *dst, int dst_pitch) | 
| 2264 | { | 
| 2265 |     switch (src_format) { | 
| 2266 |     case SDL_PIXELFORMAT_YUY2: | 
| 2267 |         switch (dst_format) { | 
| 2268 |         case SDL_PIXELFORMAT_UYVY: | 
| 2269 |             return SDL_ConvertPixels_YUY2_to_UYVY(width, height, src, src_pitch, dst, dst_pitch); | 
| 2270 |         case SDL_PIXELFORMAT_YVYU: | 
| 2271 |             return SDL_ConvertPixels_YUY2_to_YVYU(width, height, src, src_pitch, dst, dst_pitch); | 
| 2272 |         default: | 
| 2273 |             break; | 
| 2274 |         } | 
| 2275 |         break; | 
| 2276 |     case SDL_PIXELFORMAT_UYVY: | 
| 2277 |         switch (dst_format) { | 
| 2278 |         case SDL_PIXELFORMAT_YUY2: | 
| 2279 |             return SDL_ConvertPixels_UYVY_to_YUY2(width, height, src, src_pitch, dst, dst_pitch); | 
| 2280 |         case SDL_PIXELFORMAT_YVYU: | 
| 2281 |             return SDL_ConvertPixels_UYVY_to_YVYU(width, height, src, src_pitch, dst, dst_pitch); | 
| 2282 |         default: | 
| 2283 |             break; | 
| 2284 |         } | 
| 2285 |         break; | 
| 2286 |     case SDL_PIXELFORMAT_YVYU: | 
| 2287 |         switch (dst_format) { | 
| 2288 |         case SDL_PIXELFORMAT_YUY2: | 
| 2289 |             return SDL_ConvertPixels_YVYU_to_YUY2(width, height, src, src_pitch, dst, dst_pitch); | 
| 2290 |         case SDL_PIXELFORMAT_UYVY: | 
| 2291 |             return SDL_ConvertPixels_YVYU_to_UYVY(width, height, src, src_pitch, dst, dst_pitch); | 
| 2292 |         default: | 
| 2293 |             break; | 
| 2294 |         } | 
| 2295 |         break; | 
| 2296 |     default: | 
| 2297 |         break; | 
| 2298 |     } | 
| 2299 |     return SDL_SetError("SDL_ConvertPixels_Packed4_to_Packed4: Unsupported YUV conversion: %s -> %s" , SDL_GetPixelFormatName(src_format), | 
| 2300 |                         SDL_GetPixelFormatName(dst_format)); | 
| 2301 | } | 
| 2302 |  | 
| 2303 | static bool SDL_ConvertPixels_Planar2x2_to_Packed4(int width, int height, | 
| 2304 |                                                    SDL_PixelFormat src_format, const void *src, int src_pitch, | 
| 2305 |                                                    SDL_PixelFormat dst_format, void *dst, int dst_pitch) | 
| 2306 | { | 
| 2307 |     int x, y; | 
| 2308 |     const Uint8 *srcY1, *srcY2, *srcU, *srcV; | 
| 2309 |     Uint32 srcY_pitch, srcUV_pitch; | 
| 2310 |     Uint32 srcY_pitch_left, srcUV_pitch_left, srcUV_pixel_stride; | 
| 2311 |     Uint8 *dstY1, *dstY2, *dstU1, *dstU2, *dstV1, *dstV2; | 
| 2312 |     Uint32 dstY_pitch, dstUV_pitch; | 
| 2313 |     Uint32 dst_pitch_left; | 
| 2314 |  | 
| 2315 |     if (src == dst) { | 
| 2316 |         return SDL_SetError("Can't change YUV plane types in-place" ); | 
| 2317 |     } | 
| 2318 |  | 
| 2319 |     if (!GetYUVPlanes(width, height, src_format, src, src_pitch, | 
| 2320 |                       &srcY1, &srcU, &srcV, &srcY_pitch, &srcUV_pitch)) { | 
| 2321 |         return false; | 
| 2322 |     } | 
| 2323 |     srcY2 = srcY1 + srcY_pitch; | 
| 2324 |     srcY_pitch_left = (srcY_pitch - width); | 
| 2325 |  | 
| 2326 |     if (src_format == SDL_PIXELFORMAT_NV12 || src_format == SDL_PIXELFORMAT_NV21) { | 
| 2327 |         srcUV_pixel_stride = 2; | 
| 2328 |         srcUV_pitch_left = (srcUV_pitch - 2 * ((width + 1) / 2)); | 
| 2329 |     } else { | 
| 2330 |         srcUV_pixel_stride = 1; | 
| 2331 |         srcUV_pitch_left = (srcUV_pitch - ((width + 1) / 2)); | 
| 2332 |     } | 
| 2333 |  | 
| 2334 |     if (!GetYUVPlanes(width, height, dst_format, dst, dst_pitch, | 
| 2335 |                       (const Uint8 **)&dstY1, (const Uint8 **)&dstU1, (const Uint8 **)&dstV1, | 
| 2336 |                       &dstY_pitch, &dstUV_pitch)) { | 
| 2337 |         return false; | 
| 2338 |     } | 
| 2339 |     dstY2 = dstY1 + dstY_pitch; | 
| 2340 |     dstU2 = dstU1 + dstUV_pitch; | 
| 2341 |     dstV2 = dstV1 + dstUV_pitch; | 
| 2342 |     dst_pitch_left = (dstY_pitch - 4 * ((width + 1) / 2)); | 
| 2343 |  | 
| 2344 |     // Copy 2x2 blocks of pixels at a time | 
| 2345 |     for (y = 0; y < (height - 1); y += 2) { | 
| 2346 |         for (x = 0; x < (width - 1); x += 2) { | 
| 2347 |             // Row 1 | 
| 2348 |             *dstY1 = *srcY1++; | 
| 2349 |             dstY1 += 2; | 
| 2350 |             *dstY1 = *srcY1++; | 
| 2351 |             dstY1 += 2; | 
| 2352 |             *dstU1 = *srcU; | 
| 2353 |             *dstV1 = *srcV; | 
| 2354 |  | 
| 2355 |             // Row 2 | 
| 2356 |             *dstY2 = *srcY2++; | 
| 2357 |             dstY2 += 2; | 
| 2358 |             *dstY2 = *srcY2++; | 
| 2359 |             dstY2 += 2; | 
| 2360 |             *dstU2 = *srcU; | 
| 2361 |             *dstV2 = *srcV; | 
| 2362 |  | 
| 2363 |             srcU += srcUV_pixel_stride; | 
| 2364 |             srcV += srcUV_pixel_stride; | 
| 2365 |             dstU1 += 4; | 
| 2366 |             dstU2 += 4; | 
| 2367 |             dstV1 += 4; | 
| 2368 |             dstV2 += 4; | 
| 2369 |         } | 
| 2370 |  | 
| 2371 |         // Last column | 
| 2372 |         if (x == (width - 1)) { | 
| 2373 |             // Row 1 | 
| 2374 |             *dstY1 = *srcY1; | 
| 2375 |             dstY1 += 2; | 
| 2376 |             *dstY1 = *srcY1++; | 
| 2377 |             dstY1 += 2; | 
| 2378 |             *dstU1 = *srcU; | 
| 2379 |             *dstV1 = *srcV; | 
| 2380 |  | 
| 2381 |             // Row 2 | 
| 2382 |             *dstY2 = *srcY2; | 
| 2383 |             dstY2 += 2; | 
| 2384 |             *dstY2 = *srcY2++; | 
| 2385 |             dstY2 += 2; | 
| 2386 |             *dstU2 = *srcU; | 
| 2387 |             *dstV2 = *srcV; | 
| 2388 |  | 
| 2389 |             srcU += srcUV_pixel_stride; | 
| 2390 |             srcV += srcUV_pixel_stride; | 
| 2391 |             dstU1 += 4; | 
| 2392 |             dstU2 += 4; | 
| 2393 |             dstV1 += 4; | 
| 2394 |             dstV2 += 4; | 
| 2395 |         } | 
| 2396 |  | 
| 2397 |         srcY1 += srcY_pitch_left + srcY_pitch; | 
| 2398 |         srcY2 += srcY_pitch_left + srcY_pitch; | 
| 2399 |         srcU += srcUV_pitch_left; | 
| 2400 |         srcV += srcUV_pitch_left; | 
| 2401 |         dstY1 += dst_pitch_left + dstY_pitch; | 
| 2402 |         dstY2 += dst_pitch_left + dstY_pitch; | 
| 2403 |         dstU1 += dst_pitch_left + dstUV_pitch; | 
| 2404 |         dstU2 += dst_pitch_left + dstUV_pitch; | 
| 2405 |         dstV1 += dst_pitch_left + dstUV_pitch; | 
| 2406 |         dstV2 += dst_pitch_left + dstUV_pitch; | 
| 2407 |     } | 
| 2408 |  | 
| 2409 |     // Last row | 
| 2410 |     if (y == (height - 1)) { | 
| 2411 |         for (x = 0; x < (width - 1); x += 2) { | 
| 2412 |             // Row 1 | 
| 2413 |             *dstY1 = *srcY1++; | 
| 2414 |             dstY1 += 2; | 
| 2415 |             *dstY1 = *srcY1++; | 
| 2416 |             dstY1 += 2; | 
| 2417 |             *dstU1 = *srcU; | 
| 2418 |             *dstV1 = *srcV; | 
| 2419 |  | 
| 2420 |             srcU += srcUV_pixel_stride; | 
| 2421 |             srcV += srcUV_pixel_stride; | 
| 2422 |             dstU1 += 4; | 
| 2423 |             dstV1 += 4; | 
| 2424 |         } | 
| 2425 |  | 
| 2426 |         // Last column | 
| 2427 |         if (x == (width - 1)) { | 
| 2428 |             // Row 1 | 
| 2429 |             *dstY1 = *srcY1; | 
| 2430 |             dstY1 += 2; | 
| 2431 |             *dstY1 = *srcY1++; | 
| 2432 |             dstY1 += 2; | 
| 2433 |             *dstU1 = *srcU; | 
| 2434 |             *dstV1 = *srcV; | 
| 2435 |  | 
| 2436 |             srcU += srcUV_pixel_stride; | 
| 2437 |             srcV += srcUV_pixel_stride; | 
| 2438 |             dstU1 += 4; | 
| 2439 |             dstV1 += 4; | 
| 2440 |         } | 
| 2441 |     } | 
| 2442 |     return true; | 
| 2443 | } | 
| 2444 |  | 
| 2445 | static bool SDL_ConvertPixels_Packed4_to_Planar2x2(int width, int height, | 
| 2446 |                                                    SDL_PixelFormat src_format, const void *src, int src_pitch, | 
| 2447 |                                                    SDL_PixelFormat dst_format, void *dst, int dst_pitch) | 
| 2448 | { | 
| 2449 |     int x, y; | 
| 2450 |     const Uint8 *srcY1, *srcY2, *srcU1, *srcU2, *srcV1, *srcV2; | 
| 2451 |     Uint32 srcY_pitch, srcUV_pitch; | 
| 2452 |     Uint32 src_pitch_left; | 
| 2453 |     Uint8 *dstY1, *dstY2, *dstU, *dstV; | 
| 2454 |     Uint32 dstY_pitch, dstUV_pitch; | 
| 2455 |     Uint32 dstY_pitch_left, dstUV_pitch_left, dstUV_pixel_stride; | 
| 2456 |  | 
| 2457 |     if (src == dst) { | 
| 2458 |         return SDL_SetError("Can't change YUV plane types in-place" ); | 
| 2459 |     } | 
| 2460 |  | 
| 2461 |     if (!GetYUVPlanes(width, height, src_format, src, src_pitch, | 
| 2462 |                       &srcY1, &srcU1, &srcV1, &srcY_pitch, &srcUV_pitch)) { | 
| 2463 |         return false; | 
| 2464 |     } | 
| 2465 |     srcY2 = srcY1 + srcY_pitch; | 
| 2466 |     srcU2 = srcU1 + srcUV_pitch; | 
| 2467 |     srcV2 = srcV1 + srcUV_pitch; | 
| 2468 |     src_pitch_left = (srcY_pitch - 4 * ((width + 1) / 2)); | 
| 2469 |  | 
| 2470 |     if (!GetYUVPlanes(width, height, dst_format, dst, dst_pitch, | 
| 2471 |                       (const Uint8 **)&dstY1, (const Uint8 **)&dstU, (const Uint8 **)&dstV, | 
| 2472 |                       &dstY_pitch, &dstUV_pitch)) { | 
| 2473 |         return false; | 
| 2474 |     } | 
| 2475 |     dstY2 = dstY1 + dstY_pitch; | 
| 2476 |     dstY_pitch_left = (dstY_pitch - width); | 
| 2477 |  | 
| 2478 |     if (dst_format == SDL_PIXELFORMAT_NV12 || dst_format == SDL_PIXELFORMAT_NV21) { | 
| 2479 |         dstUV_pixel_stride = 2; | 
| 2480 |         dstUV_pitch_left = (dstUV_pitch - 2 * ((width + 1) / 2)); | 
| 2481 |     } else { | 
| 2482 |         dstUV_pixel_stride = 1; | 
| 2483 |         dstUV_pitch_left = (dstUV_pitch - ((width + 1) / 2)); | 
| 2484 |     } | 
| 2485 |  | 
| 2486 |     // Copy 2x2 blocks of pixels at a time | 
| 2487 |     for (y = 0; y < (height - 1); y += 2) { | 
| 2488 |         for (x = 0; x < (width - 1); x += 2) { | 
| 2489 |             // Row 1 | 
| 2490 |             *dstY1++ = *srcY1; | 
| 2491 |             srcY1 += 2; | 
| 2492 |             *dstY1++ = *srcY1; | 
| 2493 |             srcY1 += 2; | 
| 2494 |  | 
| 2495 |             // Row 2 | 
| 2496 |             *dstY2++ = *srcY2; | 
| 2497 |             srcY2 += 2; | 
| 2498 |             *dstY2++ = *srcY2; | 
| 2499 |             srcY2 += 2; | 
| 2500 |  | 
| 2501 |             *dstU = (Uint8)(((Uint32)*srcU1 + *srcU2) / 2); | 
| 2502 |             *dstV = (Uint8)(((Uint32)*srcV1 + *srcV2) / 2); | 
| 2503 |  | 
| 2504 |             srcU1 += 4; | 
| 2505 |             srcU2 += 4; | 
| 2506 |             srcV1 += 4; | 
| 2507 |             srcV2 += 4; | 
| 2508 |             dstU += dstUV_pixel_stride; | 
| 2509 |             dstV += dstUV_pixel_stride; | 
| 2510 |         } | 
| 2511 |  | 
| 2512 |         // Last column | 
| 2513 |         if (x == (width - 1)) { | 
| 2514 |             // Row 1 | 
| 2515 |             *dstY1 = *srcY1; | 
| 2516 |             srcY1 += 2; | 
| 2517 |             *dstY1++ = *srcY1; | 
| 2518 |             srcY1 += 2; | 
| 2519 |  | 
| 2520 |             // Row 2 | 
| 2521 |             *dstY2 = *srcY2; | 
| 2522 |             srcY2 += 2; | 
| 2523 |             *dstY2++ = *srcY2; | 
| 2524 |             srcY2 += 2; | 
| 2525 |  | 
| 2526 |             *dstU = (Uint8)(((Uint32)*srcU1 + *srcU2) / 2); | 
| 2527 |             *dstV = (Uint8)(((Uint32)*srcV1 + *srcV2) / 2); | 
| 2528 |  | 
| 2529 |             srcU1 += 4; | 
| 2530 |             srcU2 += 4; | 
| 2531 |             srcV1 += 4; | 
| 2532 |             srcV2 += 4; | 
| 2533 |             dstU += dstUV_pixel_stride; | 
| 2534 |             dstV += dstUV_pixel_stride; | 
| 2535 |         } | 
| 2536 |  | 
| 2537 |         srcY1 += src_pitch_left + srcY_pitch; | 
| 2538 |         srcY2 += src_pitch_left + srcY_pitch; | 
| 2539 |         srcU1 += src_pitch_left + srcUV_pitch; | 
| 2540 |         srcU2 += src_pitch_left + srcUV_pitch; | 
| 2541 |         srcV1 += src_pitch_left + srcUV_pitch; | 
| 2542 |         srcV2 += src_pitch_left + srcUV_pitch; | 
| 2543 |         dstY1 += dstY_pitch_left + dstY_pitch; | 
| 2544 |         dstY2 += dstY_pitch_left + dstY_pitch; | 
| 2545 |         dstU += dstUV_pitch_left; | 
| 2546 |         dstV += dstUV_pitch_left; | 
| 2547 |     } | 
| 2548 |  | 
| 2549 |     // Last row | 
| 2550 |     if (y == (height - 1)) { | 
| 2551 |         for (x = 0; x < (width - 1); x += 2) { | 
| 2552 |             *dstY1++ = *srcY1; | 
| 2553 |             srcY1 += 2; | 
| 2554 |             *dstY1++ = *srcY1; | 
| 2555 |             srcY1 += 2; | 
| 2556 |  | 
| 2557 |             *dstU = *srcU1; | 
| 2558 |             *dstV = *srcV1; | 
| 2559 |  | 
| 2560 |             srcU1 += 4; | 
| 2561 |             srcV1 += 4; | 
| 2562 |             dstU += dstUV_pixel_stride; | 
| 2563 |             dstV += dstUV_pixel_stride; | 
| 2564 |         } | 
| 2565 |  | 
| 2566 |         // Last column | 
| 2567 |         if (x == (width - 1)) { | 
| 2568 |             *dstY1 = *srcY1; | 
| 2569 |             *dstU = *srcU1; | 
| 2570 |             *dstV = *srcV1; | 
| 2571 |         } | 
| 2572 |     } | 
| 2573 |     return true; | 
| 2574 | } | 
| 2575 |  | 
| 2576 | #endif // SDL_HAVE_YUV | 
| 2577 |  | 
| 2578 | bool SDL_ConvertPixels_YUV_to_YUV(int width, int height, | 
| 2579 |                                   SDL_PixelFormat src_format, SDL_Colorspace src_colorspace, SDL_PropertiesID src_properties, const void *src, int src_pitch, | 
| 2580 |                                   SDL_PixelFormat dst_format, SDL_Colorspace dst_colorspace, SDL_PropertiesID dst_properties, void *dst, int dst_pitch) | 
| 2581 | { | 
| 2582 | #ifdef SDL_HAVE_YUV | 
| 2583 |     if (src_colorspace != dst_colorspace) { | 
| 2584 |         return SDL_SetError("SDL_ConvertPixels_YUV_to_YUV: colorspace conversion not supported" ); | 
| 2585 |     } | 
| 2586 |  | 
| 2587 |     if (src_format == dst_format) { | 
| 2588 |         if (src == dst) { | 
| 2589 |             // Nothing to do | 
| 2590 |             return true; | 
| 2591 |         } | 
| 2592 |         return SDL_ConvertPixels_YUV_to_YUV_Copy(width, height, src_format, src, src_pitch, dst, dst_pitch); | 
| 2593 |     } | 
| 2594 |  | 
| 2595 |     if (IsPlanar2x2Format(src_format) && IsPlanar2x2Format(dst_format)) { | 
| 2596 |         return SDL_ConvertPixels_Planar2x2_to_Planar2x2(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch); | 
| 2597 |     } else if (IsPacked4Format(src_format) && IsPacked4Format(dst_format)) { | 
| 2598 |         return SDL_ConvertPixels_Packed4_to_Packed4(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch); | 
| 2599 |     } else if (IsPlanar2x2Format(src_format) && IsPacked4Format(dst_format)) { | 
| 2600 |         return SDL_ConvertPixels_Planar2x2_to_Packed4(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch); | 
| 2601 |     } else if (IsPacked4Format(src_format) && IsPlanar2x2Format(dst_format)) { | 
| 2602 |         return SDL_ConvertPixels_Packed4_to_Planar2x2(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch); | 
| 2603 |     } else { | 
| 2604 |         return SDL_SetError("SDL_ConvertPixels_YUV_to_YUV: Unsupported YUV conversion: %s -> %s" , SDL_GetPixelFormatName(src_format), | 
| 2605 |                             SDL_GetPixelFormatName(dst_format)); | 
| 2606 |     } | 
| 2607 | #else | 
| 2608 |     return SDL_SetError("SDL not built with YUV support" ); | 
| 2609 | #endif | 
| 2610 | } | 
| 2611 |  |