Atlas - SDL_yuv.c

Home / ext / SDL / src / video Lines: 1 | Size: 90803 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 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 30static 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 */ 37bool 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 160static 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 190static 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 195static bool IsPacked4Format(Uint32 format) 196{ 197 return format == SDL_PIXELFORMAT_YUY2 || format == SDL_PIXELFORMAT_UYVY || format == SDL_PIXELFORMAT_YVYU; 198} 199 200static 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 306static 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 413static 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 425static 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 465static 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 476static 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 589bool 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 YCbCrType yuv_type = YCBCR_601_LIMITED; 599 600 if (!GetYUVPlanes(width, height, src_format, src, src_pitch, &y, &u, &v, &y_stride, &uv_stride)) { 601 return false; 602 } 603 604 if (!GetYUVConversionType(src_colorspace, &yuv_type)) { 605 return false; 606 } 607 608 if (yuv_rgb_sse(src_format, dst_format, width, height, y, u, v, y_stride, uv_stride, (Uint8 *)dst, dst_pitch, yuv_type)) { 609 return true; 610 } 611 612 if (yuv_rgb_lsx(src_format, dst_format, width, height, y, u, v, y_stride, uv_stride, (Uint8 *)dst, dst_pitch, yuv_type)) { 613 return true; 614 } 615 616 if (yuv_rgb_std(src_format, dst_format, width, height, y, u, v, y_stride, uv_stride, (Uint8 *)dst, dst_pitch, yuv_type)) { 617 return true; 618 } 619 620 // No fast path for the RGB format, instead convert using an intermediate buffer 621 if (src_format == SDL_PIXELFORMAT_P010 && dst_format != SDL_PIXELFORMAT_XBGR2101010) { 622 bool result; 623 void *tmp; 624 int tmp_pitch = (width * sizeof(Uint32)); 625 626 tmp = SDL_malloc((size_t)tmp_pitch * height); 627 if (!tmp) { 628 return false; 629 } 630 631 // convert src/src_format to tmp/XBGR2101010 632 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); 633 if (!result) { 634 SDL_free(tmp); 635 return false; 636 } 637 638 // convert tmp/XBGR2101010 to dst/RGB 639 result = SDL_ConvertPixelsAndColorspace(width, height, SDL_PIXELFORMAT_XBGR2101010, src_colorspace, src_properties, tmp, tmp_pitch, dst_format, dst_colorspace, dst_properties, dst, dst_pitch); 640 SDL_free(tmp); 641 return result; 642 } 643 644 if (dst_format != SDL_PIXELFORMAT_ARGB8888) { 645 bool result; 646 void *tmp; 647 int tmp_pitch = (width * sizeof(Uint32)); 648 649 tmp = SDL_malloc((size_t)tmp_pitch * height); 650 if (!tmp) { 651 return false; 652 } 653 654 // convert src/src_format to tmp/ARGB8888 655 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); 656 if (!result) { 657 SDL_free(tmp); 658 return false; 659 } 660 661 // convert tmp/ARGB8888 to dst/RGB 662 result = SDL_ConvertPixelsAndColorspace(width, height, SDL_PIXELFORMAT_ARGB8888, SDL_COLORSPACE_SRGB, 0, tmp, tmp_pitch, dst_format, dst_colorspace, dst_properties, dst, dst_pitch); 663 SDL_free(tmp); 664 return result; 665 } 666 667 return SDL_SetError("Unsupported YUV conversion"); 668} 669 670struct RGB2YUVFactors 671{ 672 int y_offset; 673 float y[3]; // Rfactor, Gfactor, Bfactor 674 float u[3]; // Rfactor, Gfactor, Bfactor 675 float v[3]; // Rfactor, Gfactor, Bfactor 676}; 677 678static struct RGB2YUVFactors RGB2YUVFactorTables[] = { 679 // ITU-T T.871 (JPEG) 680 { 681 0, 682 { 0.2990f, 0.5870f, 0.1140f }, 683 { -0.1687f, -0.3313f, 0.5000f }, 684 { 0.5000f, -0.4187f, -0.0813f }, 685 }, 686 // ITU-R BT.601-7 687 { 688 16, 689 { 0.2568f, 0.5041f, 0.0979f }, 690 { -0.1482f, -0.2910f, 0.4392f }, 691 { 0.4392f, -0.3678f, -0.0714f }, 692 }, 693 // ITU-R BT.709-6 full range 694 { 695 0, 696 { 0.2126f, 0.7152f, 0.0722f }, 697 { -0.1141f, -0.3839f, 0.498f }, 698 { 0.498f, -0.4524f, -0.0457f }, 699 }, 700 // ITU-R BT.709-6 701 { 702 16, 703 { 0.1826f, 0.6142f, 0.0620f }, 704 { -0.1006f, -0.3386f, 0.4392f }, 705 { 0.4392f, -0.3989f, -0.0403f }, 706 }, 707 // ITU-R BT.2020 10-bit full range 708 { 709 0, 710 { 0.2627f, 0.6780f, 0.0593f }, 711 { -0.1395f, -0.3600f, 0.4995f }, 712 { 0.4995f, -0.4593f, -0.0402f }, 713 }, 714}; 715 716static 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) 717{ 718 const int src_pitch_x_2 = src_pitch * 2; 719 const int height_half = height / 2; 720 const int height_remainder = (height & 0x1); 721 const int width_half = width / 2; 722 const int width_remainder = (width & 0x1); 723 int i, j; 724 725 const struct RGB2YUVFactors *cvt = &RGB2YUVFactorTables[yuv_type]; 726 727#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) 728#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) 729#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) 730 731#define READ_2x2_PIXELS \ 732 const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i]; \ 733 const Uint32 p2 = ((const Uint32 *)curr_row)[2 * i + 1]; \ 734 const Uint32 p3 = ((const Uint32 *)next_row)[2 * i]; \ 735 const Uint32 p4 = ((const Uint32 *)next_row)[2 * i + 1]; \ 736 const Uint32 r = ((p1 & 0x00ff0000) + (p2 & 0x00ff0000) + (p3 & 0x00ff0000) + (p4 & 0x00ff0000)) >> 18; \ 737 const Uint32 g = ((p1 & 0x0000ff00) + (p2 & 0x0000ff00) + (p3 & 0x0000ff00) + (p4 & 0x0000ff00)) >> 10; \ 738 const Uint32 b = ((p1 & 0x000000ff) + (p2 & 0x000000ff) + (p3 & 0x000000ff) + (p4 & 0x000000ff)) >> 2 739 740#define READ_2x1_PIXELS \ 741 const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i]; \ 742 const Uint32 p2 = ((const Uint32 *)next_row)[2 * i]; \ 743 const Uint32 r = ((p1 & 0x00ff0000) + (p2 & 0x00ff0000)) >> 17; \ 744 const Uint32 g = ((p1 & 0x0000ff00) + (p2 & 0x0000ff00)) >> 9; \ 745 const Uint32 b = ((p1 & 0x000000ff) + (p2 & 0x000000ff)) >> 1 746 747#define READ_1x2_PIXELS \ 748 const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i]; \ 749 const Uint32 p2 = ((const Uint32 *)curr_row)[2 * i + 1]; \ 750 const Uint32 r = ((p1 & 0x00ff0000) + (p2 & 0x00ff0000)) >> 17; \ 751 const Uint32 g = ((p1 & 0x0000ff00) + (p2 & 0x0000ff00)) >> 9; \ 752 const Uint32 b = ((p1 & 0x000000ff) + (p2 & 0x000000ff)) >> 1 753 754#define READ_1x1_PIXEL \ 755 const Uint32 p = ((const Uint32 *)curr_row)[2 * i]; \ 756 const Uint32 r = (p & 0x00ff0000) >> 16; \ 757 const Uint32 g = (p & 0x0000ff00) >> 8; \ 758 const Uint32 b = (p & 0x000000ff) 759 760#define READ_TWO_RGB_PIXELS \ 761 const Uint32 p = ((const Uint32 *)curr_row)[2 * i]; \ 762 const Uint32 r = (p & 0x00ff0000) >> 16; \ 763 const Uint32 g = (p & 0x0000ff00) >> 8; \ 764 const Uint32 b = (p & 0x000000ff); \ 765 const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i + 1]; \ 766 const Uint32 r1 = (p1 & 0x00ff0000) >> 16; \ 767 const Uint32 g1 = (p1 & 0x0000ff00) >> 8; \ 768 const Uint32 b1 = (p1 & 0x000000ff); \ 769 const Uint32 R = (r + r1) / 2; \ 770 const Uint32 G = (g + g1) / 2; \ 771 const Uint32 B = (b + b1) / 2 772 773#define READ_ONE_RGB_PIXEL READ_1x1_PIXEL 774 775 switch (dst_format) { 776 case SDL_PIXELFORMAT_YV12: 777 case SDL_PIXELFORMAT_IYUV: 778 case SDL_PIXELFORMAT_NV12: 779 case SDL_PIXELFORMAT_NV21: 780 { 781 const Uint8 *curr_row, *next_row; 782 783 Uint8 *plane_y; 784 Uint8 *plane_u; 785 Uint8 *plane_v; 786 Uint8 *plane_interleaved_uv; 787 Uint32 y_stride, uv_stride, y_skip, uv_skip; 788 789 if (!GetYUVPlanes(width, height, dst_format, dst, dst_pitch, 790 (const Uint8 **)&plane_y, (const Uint8 **)&plane_u, (const Uint8 **)&plane_v, 791 &y_stride, &uv_stride)) { 792 return false; 793 } 794 795 plane_interleaved_uv = (plane_y + height * y_stride); 796 y_skip = (y_stride - width); 797 798 curr_row = (const Uint8 *)src; 799 800 // Write Y plane 801 for (j = 0; j < height; j++) { 802 for (i = 0; i < width; i++) { 803 const Uint32 p1 = ((const Uint32 *)curr_row)[i]; 804 const Uint32 r = (p1 & 0x00ff0000) >> 16; 805 const Uint32 g = (p1 & 0x0000ff00) >> 8; 806 const Uint32 b = (p1 & 0x000000ff); 807 *plane_y++ = MAKE_Y(r, g, b); 808 } 809 plane_y += y_skip; 810 curr_row += src_pitch; 811 } 812 813 curr_row = (const Uint8 *)src; 814 next_row = (const Uint8 *)src; 815 next_row += src_pitch; 816 817 if (dst_format == SDL_PIXELFORMAT_YV12 || dst_format == SDL_PIXELFORMAT_IYUV) { 818 // Write UV planes, not interleaved 819 uv_skip = (uv_stride - (width + 1) / 2); 820 for (j = 0; j < height_half; j++) { 821 for (i = 0; i < width_half; i++) { 822 READ_2x2_PIXELS; 823 *plane_u++ = MAKE_U(r, g, b); 824 *plane_v++ = MAKE_V(r, g, b); 825 } 826 if (width_remainder) { 827 READ_2x1_PIXELS; 828 *plane_u++ = MAKE_U(r, g, b); 829 *plane_v++ = MAKE_V(r, g, b); 830 } 831 plane_u += uv_skip; 832 plane_v += uv_skip; 833 curr_row += src_pitch_x_2; 834 next_row += src_pitch_x_2; 835 } 836 if (height_remainder) { 837 for (i = 0; i < width_half; i++) { 838 READ_1x2_PIXELS; 839 *plane_u++ = MAKE_U(r, g, b); 840 *plane_v++ = MAKE_V(r, g, b); 841 } 842 if (width_remainder) { 843 READ_1x1_PIXEL; 844 *plane_u++ = MAKE_U(r, g, b); 845 *plane_v++ = MAKE_V(r, g, b); 846 } 847 plane_u += uv_skip; 848 plane_v += uv_skip; 849 } 850 } else if (dst_format == SDL_PIXELFORMAT_NV12) { 851 uv_skip = (uv_stride - ((width + 1) / 2) * 2); 852 for (j = 0; j < height_half; j++) { 853 for (i = 0; i < width_half; i++) { 854 READ_2x2_PIXELS; 855 *plane_interleaved_uv++ = MAKE_U(r, g, b); 856 *plane_interleaved_uv++ = MAKE_V(r, g, b); 857 } 858 if (width_remainder) { 859 READ_2x1_PIXELS; 860 *plane_interleaved_uv++ = MAKE_U(r, g, b); 861 *plane_interleaved_uv++ = MAKE_V(r, g, b); 862 } 863 plane_interleaved_uv += uv_skip; 864 curr_row += src_pitch_x_2; 865 next_row += src_pitch_x_2; 866 } 867 if (height_remainder) { 868 for (i = 0; i < width_half; i++) { 869 READ_1x2_PIXELS; 870 *plane_interleaved_uv++ = MAKE_U(r, g, b); 871 *plane_interleaved_uv++ = MAKE_V(r, g, b); 872 } 873 if (width_remainder) { 874 READ_1x1_PIXEL; 875 *plane_interleaved_uv++ = MAKE_U(r, g, b); 876 *plane_interleaved_uv++ = MAKE_V(r, g, b); 877 } 878 } 879 } else /* dst_format == SDL_PIXELFORMAT_NV21 */ { 880 uv_skip = (uv_stride - ((width + 1) / 2) * 2); 881 for (j = 0; j < height_half; j++) { 882 for (i = 0; i < width_half; i++) { 883 READ_2x2_PIXELS; 884 *plane_interleaved_uv++ = MAKE_V(r, g, b); 885 *plane_interleaved_uv++ = MAKE_U(r, g, b); 886 } 887 if (width_remainder) { 888 READ_2x1_PIXELS; 889 *plane_interleaved_uv++ = MAKE_V(r, g, b); 890 *plane_interleaved_uv++ = MAKE_U(r, g, b); 891 } 892 plane_interleaved_uv += uv_skip; 893 curr_row += src_pitch_x_2; 894 next_row += src_pitch_x_2; 895 } 896 if (height_remainder) { 897 for (i = 0; i < width_half; i++) { 898 READ_1x2_PIXELS; 899 *plane_interleaved_uv++ = MAKE_V(r, g, b); 900 *plane_interleaved_uv++ = MAKE_U(r, g, b); 901 } 902 if (width_remainder) { 903 READ_1x1_PIXEL; 904 *plane_interleaved_uv++ = MAKE_V(r, g, b); 905 *plane_interleaved_uv++ = MAKE_U(r, g, b); 906 } 907 } 908 } 909 } break; 910 911 case SDL_PIXELFORMAT_YUY2: 912 case SDL_PIXELFORMAT_UYVY: 913 case SDL_PIXELFORMAT_YVYU: 914 { 915 const Uint8 *curr_row = (const Uint8 *)src; 916 Uint8 *plane = (Uint8 *)dst; 917 const int row_size = (4 * ((width + 1) / 2)); 918 int plane_skip; 919 920 if (dst_pitch < row_size) { 921 return SDL_SetError("Destination pitch is too small, expected at least %d", row_size); 922 } 923 plane_skip = (dst_pitch - row_size); 924 925 // Write YUV plane, packed 926 if (dst_format == SDL_PIXELFORMAT_YUY2) { 927 for (j = 0; j < height; j++) { 928 for (i = 0; i < width_half; i++) { 929 READ_TWO_RGB_PIXELS; 930 // Y U Y1 V 931 *plane++ = MAKE_Y(r, g, b); 932 *plane++ = MAKE_U(R, G, B); 933 *plane++ = MAKE_Y(r1, g1, b1); 934 *plane++ = MAKE_V(R, G, B); 935 } 936 if (width_remainder) { 937 READ_ONE_RGB_PIXEL; 938 // Y U Y V 939 *plane++ = MAKE_Y(r, g, b); 940 *plane++ = MAKE_U(r, g, b); 941 *plane++ = MAKE_Y(r, g, b); 942 *plane++ = MAKE_V(r, g, b); 943 } 944 plane += plane_skip; 945 curr_row += src_pitch; 946 } 947 } else if (dst_format == SDL_PIXELFORMAT_UYVY) { 948 for (j = 0; j < height; j++) { 949 for (i = 0; i < width_half; i++) { 950 READ_TWO_RGB_PIXELS; 951 // U Y V Y1 952 *plane++ = MAKE_U(R, G, B); 953 *plane++ = MAKE_Y(r, g, b); 954 *plane++ = MAKE_V(R, G, B); 955 *plane++ = MAKE_Y(r1, g1, b1); 956 } 957 if (width_remainder) { 958 READ_ONE_RGB_PIXEL; 959 // U Y V Y 960 *plane++ = MAKE_U(r, g, b); 961 *plane++ = MAKE_Y(r, g, b); 962 *plane++ = MAKE_V(r, g, b); 963 *plane++ = MAKE_Y(r, g, b); 964 } 965 plane += plane_skip; 966 curr_row += src_pitch; 967 } 968 } else if (dst_format == SDL_PIXELFORMAT_YVYU) { 969 for (j = 0; j < height; j++) { 970 for (i = 0; i < width_half; i++) { 971 READ_TWO_RGB_PIXELS; 972 // Y V Y1 U 973 *plane++ = MAKE_Y(r, g, b); 974 *plane++ = MAKE_V(R, G, B); 975 *plane++ = MAKE_Y(r1, g1, b1); 976 *plane++ = MAKE_U(R, G, B); 977 } 978 if (width_remainder) { 979 READ_ONE_RGB_PIXEL; 980 // Y V Y U 981 *plane++ = MAKE_Y(r, g, b); 982 *plane++ = MAKE_V(r, g, b); 983 *plane++ = MAKE_Y(r, g, b); 984 *plane++ = MAKE_U(r, g, b); 985 } 986 plane += plane_skip; 987 curr_row += src_pitch; 988 } 989 } 990 } break; 991 992 default: 993 return SDL_SetError("Unsupported YUV destination format: %s", SDL_GetPixelFormatName(dst_format)); 994 } 995#undef MAKE_Y 996#undef MAKE_U 997#undef MAKE_V 998#undef READ_2x2_PIXELS 999#undef READ_2x1_PIXELS 1000#undef READ_1x2_PIXELS 1001#undef READ_1x1_PIXEL 1002#undef READ_TWO_RGB_PIXELS 1003#undef READ_ONE_RGB_PIXEL 1004 return true; 1005} 1006 1007static 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) 1008{ 1009 const int src_pitch_x_2 = src_pitch * 2; 1010 const int height_half = height / 2; 1011 const int height_remainder = (height & 0x1); 1012 const int width_half = width / 2; 1013 const int width_remainder = (width & 0x1); 1014 int i, j; 1015 1016 const struct RGB2YUVFactors *cvt = &RGB2YUVFactorTables[yuv_type]; 1017 1018#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) 1019#define MAKE_U(r, g, b) (Uint16)(((int)(cvt->u[0] * (r) + cvt->u[1] * (g) + cvt->u[2] * (b) + 0.5f) + 512) << 6) 1020#define MAKE_V(r, g, b) (Uint16)(((int)(cvt->v[0] * (r) + cvt->v[1] * (g) + cvt->v[2] * (b) + 0.5f) + 512) << 6) 1021 1022#define READ_2x2_PIXELS \ 1023 const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i]; \ 1024 const Uint32 p2 = ((const Uint32 *)curr_row)[2 * i + 1]; \ 1025 const Uint32 p3 = ((const Uint32 *)next_row)[2 * i]; \ 1026 const Uint32 p4 = ((const Uint32 *)next_row)[2 * i + 1]; \ 1027 const Uint32 r = ((p1 & 0x000003ff) + (p2 & 0x000003ff) + (p3 & 0x000003ff) + (p4 & 0x000003ff)) >> 2; \ 1028 const Uint32 g = ((p1 & 0x000ffc00) + (p2 & 0x000ffc00) + (p3 & 0x000ffc00) + (p4 & 0x000ffc00)) >> 12; \ 1029 const Uint32 b = ((p1 & 0x3ff00000) + (p2 & 0x3ff00000) + (p3 & 0x3ff00000) + (p4 & 0x3ff00000)) >> 22 1030 1031#define READ_2x1_PIXELS \ 1032 const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i]; \ 1033 const Uint32 p2 = ((const Uint32 *)next_row)[2 * i]; \ 1034 const Uint32 r = ((p1 & 0x000003ff) + (p2 & 0x000003ff)) >> 1; \ 1035 const Uint32 g = ((p1 & 0x000ffc00) + (p2 & 0x000ffc00)) >> 11; \ 1036 const Uint32 b = ((p1 & 0x3ff00000) + (p2 & 0x3ff00000)) >> 21 1037 1038#define READ_1x2_PIXELS \ 1039 const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i]; \ 1040 const Uint32 p2 = ((const Uint32 *)curr_row)[2 * i + 1]; \ 1041 const Uint32 r = ((p1 & 0x000003ff) + (p2 & 0x000003ff)) >> 1; \ 1042 const Uint32 g = ((p1 & 0x000ffc00) + (p2 & 0x000ffc00)) >> 11; \ 1043 const Uint32 b = ((p1 & 0x3ff00000) + (p2 & 0x3ff00000)) >> 21 1044 1045#define READ_1x1_PIXEL \ 1046 const Uint32 p = ((const Uint32 *)curr_row)[2 * i]; \ 1047 const Uint32 r = (p & 0x000003ff); \ 1048 const Uint32 g = (p & 0x000ffc00) >> 10; \ 1049 const Uint32 b = (p & 0x3ff00000) >> 20 1050 1051 const Uint8 *curr_row, *next_row; 1052 1053 Uint16 *plane_y; 1054 Uint16 *plane_u; 1055 Uint16 *plane_v; 1056 Uint16 *plane_interleaved_uv; 1057 Uint32 y_stride, uv_stride, y_skip, uv_skip; 1058 1059 if (!GetYUVPlanes(width, height, dst_format, dst, dst_pitch, 1060 (const Uint8 **)&plane_y, (const Uint8 **)&plane_u, (const Uint8 **)&plane_v, 1061 &y_stride, &uv_stride)) { 1062 return false; 1063 } 1064 1065 y_stride /= sizeof(Uint16); 1066 uv_stride /= sizeof(Uint16); 1067 1068 plane_interleaved_uv = (plane_y + height * y_stride); 1069 y_skip = (y_stride - width); 1070 1071 curr_row = (const Uint8 *)src; 1072 1073 // Write Y plane 1074 for (j = 0; j < height; j++) { 1075 for (i = 0; i < width; i++) { 1076 const Uint32 p1 = ((const Uint32 *)curr_row)[i]; 1077 const Uint32 r = (p1 >> 0) & 0x03ff; 1078 const Uint32 g = (p1 >> 10) & 0x03ff; 1079 const Uint32 b = (p1 >> 20) & 0x03ff; 1080 *plane_y++ = MAKE_Y(r, g, b); 1081 } 1082 plane_y += y_skip; 1083 curr_row += src_pitch; 1084 } 1085 1086 curr_row = (const Uint8 *)src; 1087 next_row = (const Uint8 *)src; 1088 next_row += src_pitch; 1089 1090 uv_skip = (uv_stride - ((width + 1) / 2) * 2); 1091 for (j = 0; j < height_half; j++) { 1092 for (i = 0; i < width_half; i++) { 1093 READ_2x2_PIXELS; 1094 *plane_interleaved_uv++ = MAKE_U(r, g, b); 1095 *plane_interleaved_uv++ = MAKE_V(r, g, b); 1096 } 1097 if (width_remainder) { 1098 READ_2x1_PIXELS; 1099 *plane_interleaved_uv++ = MAKE_U(r, g, b); 1100 *plane_interleaved_uv++ = MAKE_V(r, g, b); 1101 } 1102 plane_interleaved_uv += uv_skip; 1103 curr_row += src_pitch_x_2; 1104 next_row += src_pitch_x_2; 1105 } 1106 if (height_remainder) { 1107 for (i = 0; i < width_half; i++) { 1108 READ_1x2_PIXELS; 1109 *plane_interleaved_uv++ = MAKE_U(r, g, b); 1110 *plane_interleaved_uv++ = MAKE_V(r, g, b); 1111 } 1112 if (width_remainder) { 1113 READ_1x1_PIXEL; 1114 *plane_interleaved_uv++ = MAKE_U(r, g, b); 1115 *plane_interleaved_uv++ = MAKE_V(r, g, b); 1116 } 1117 } 1118 1119#undef MAKE_Y 1120#undef MAKE_U 1121#undef MAKE_V 1122#undef READ_2x2_PIXELS 1123#undef READ_2x1_PIXELS 1124#undef READ_1x2_PIXELS 1125#undef READ_1x1_PIXEL 1126 return true; 1127} 1128 1129bool SDL_ConvertPixels_RGB_to_YUV(int width, int height, 1130 SDL_PixelFormat src_format, SDL_Colorspace src_colorspace, SDL_PropertiesID src_properties, const void *src, int src_pitch, 1131 SDL_PixelFormat dst_format, SDL_Colorspace dst_colorspace, SDL_PropertiesID dst_properties, void *dst, int dst_pitch) 1132{ 1133 YCbCrType yuv_type = YCBCR_601_LIMITED; 1134 1135 if (!GetYUVConversionType(dst_colorspace, &yuv_type)) { 1136 return false; 1137 } 1138 1139#if 0 // Doesn't handle odd widths 1140 // RGB24 to FOURCC 1141 if (src_format == SDL_PIXELFORMAT_RGB24) { 1142 Uint8 *y; 1143 Uint8 *u; 1144 Uint8 *v; 1145 Uint32 y_stride; 1146 Uint32 uv_stride; 1147 1148 if (GetYUVPlanes(width, height, dst_format, dst, dst_pitch, (const Uint8 **)&y, (const Uint8 **)&u, (const Uint8 **)&v, &y_stride, &uv_stride) < 0) { 1149 return false; 1150 } 1151 1152 rgb24_yuv420_std(width, height, src, src_pitch, y, u, v, y_stride, uv_stride, yuv_type); 1153 return true; 1154 } 1155#endif 1156 1157 // ARGB8888 to FOURCC 1158 if (src_format == SDL_PIXELFORMAT_ARGB8888 || src_format == SDL_PIXELFORMAT_XRGB8888) { 1159 return SDL_ConvertPixels_XRGB8888_to_YUV(width, height, src, src_pitch, dst_format, dst, dst_pitch, yuv_type); 1160 } 1161 1162 if (dst_format == SDL_PIXELFORMAT_P010) { 1163 if (src_format == SDL_PIXELFORMAT_XBGR2101010) { 1164 return SDL_ConvertPixels_XBGR2101010_to_P010(width, height, src, src_pitch, dst_format, dst, dst_pitch, yuv_type); 1165 } 1166 1167 // We currently only support converting from XBGR2101010 to P010 1168 bool result; 1169 void *tmp; 1170 int tmp_pitch = (width * sizeof(Uint32)); 1171 1172 tmp = SDL_malloc((size_t)tmp_pitch * height); 1173 if (!tmp) { 1174 return false; 1175 } 1176 1177 // convert src/src_format to tmp/XBGR2101010 1178 result = SDL_ConvertPixelsAndColorspace(width, height, src_format, src_colorspace, src_properties, src, src_pitch, SDL_PIXELFORMAT_XBGR2101010, dst_colorspace, dst_properties, tmp, tmp_pitch); 1179 if (!result) { 1180 SDL_free(tmp); 1181 return false; 1182 } 1183 1184 // convert tmp/XBGR2101010 to dst/P010 1185 result = SDL_ConvertPixels_XBGR2101010_to_P010(width, height, tmp, tmp_pitch, dst_format, dst, dst_pitch, yuv_type); 1186 SDL_free(tmp); 1187 return result; 1188 } 1189 1190 // not ARGB8888 to FOURCC : need an intermediate conversion 1191 { 1192 bool result; 1193 void *tmp; 1194 int tmp_pitch = (width * sizeof(Uint32)); 1195 1196 tmp = SDL_malloc((size_t)tmp_pitch * height); 1197 if (!tmp) { 1198 return false; 1199 } 1200 1201 // convert src/src_format to tmp/XRGB8888 1202 result = SDL_ConvertPixelsAndColorspace(width, height, src_format, src_colorspace, src_properties, src, src_pitch, SDL_PIXELFORMAT_XRGB8888, SDL_COLORSPACE_SRGB, 0, tmp, tmp_pitch); 1203 if (!result) { 1204 SDL_free(tmp); 1205 return false; 1206 } 1207 1208 // convert tmp/XRGB8888 to dst/FOURCC 1209 result = SDL_ConvertPixels_XRGB8888_to_YUV(width, height, tmp, tmp_pitch, dst_format, dst, dst_pitch, yuv_type); 1210 SDL_free(tmp); 1211 return result; 1212 } 1213} 1214 1215static 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) 1216{ 1217 int i; 1218 1219 if (IsPlanar2x2Format(format)) { 1220 // Y plane 1221 for (i = height; i--;) { 1222 SDL_memcpy(dst, src, width); 1223 src = (const Uint8 *)src + src_pitch; 1224 dst = (Uint8 *)dst + dst_pitch; 1225 } 1226 1227 if (format == SDL_PIXELFORMAT_YV12 || format == SDL_PIXELFORMAT_IYUV) { 1228 // U and V planes are a quarter the size of the Y plane, rounded up 1229 width = (width + 1) / 2; 1230 height = (height + 1) / 2; 1231 src_pitch = (src_pitch + 1) / 2; 1232 dst_pitch = (dst_pitch + 1) / 2; 1233 for (i = height * 2; i--;) { 1234 SDL_memcpy(dst, src, width); 1235 src = (const Uint8 *)src + src_pitch; 1236 dst = (Uint8 *)dst + dst_pitch; 1237 } 1238 } else if (format == SDL_PIXELFORMAT_NV12 || format == SDL_PIXELFORMAT_NV21) { 1239 // U/V plane is half the height of the Y plane, rounded up 1240 height = (height + 1) / 2; 1241 width = ((width + 1) / 2) * 2; 1242 src_pitch = ((src_pitch + 1) / 2) * 2; 1243 dst_pitch = ((dst_pitch + 1) / 2) * 2; 1244 for (i = height; i--;) { 1245 SDL_memcpy(dst, src, width); 1246 src = (const Uint8 *)src + src_pitch; 1247 dst = (Uint8 *)dst + dst_pitch; 1248 } 1249 } else if (format == SDL_PIXELFORMAT_P010) { 1250 // U/V plane is half the height of the Y plane, rounded up 1251 height = (height + 1) / 2; 1252 width = ((width + 1) / 2) * 2; 1253 src_pitch = ((src_pitch + 1) / 2) * 2; 1254 dst_pitch = ((dst_pitch + 1) / 2) * 2; 1255 for (i = height; i--;) { 1256 SDL_memcpy(dst, src, width * sizeof(Uint16)); 1257 src = (const Uint8 *)src + src_pitch; 1258 dst = (Uint8 *)dst + dst_pitch; 1259 } 1260 } 1261 return true; 1262 } 1263 1264 if (IsPacked4Format(format)) { 1265 // Packed planes 1266 width = 4 * ((width + 1) / 2); 1267 for (i = height; i--;) { 1268 SDL_memcpy(dst, src, width); 1269 src = (const Uint8 *)src + src_pitch; 1270 dst = (Uint8 *)dst + dst_pitch; 1271 } 1272 return true; 1273 } 1274 1275 return SDL_SetError("SDL_ConvertPixels_YUV_to_YUV_Copy: Unsupported YUV format: %s", SDL_GetPixelFormatName(format)); 1276} 1277 1278static bool SDL_ConvertPixels_SwapUVPlanes(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 1279{ 1280 int y; 1281 const int UVwidth = (width + 1) / 2; 1282 const int UVheight = (height + 1) / 2; 1283 1284 // Skip the Y plane 1285 src = (const Uint8 *)src + height * src_pitch; 1286 dst = (Uint8 *)dst + height * dst_pitch; 1287 1288 if (src == dst) { 1289 int UVpitch = (dst_pitch + 1) / 2; 1290 Uint8 *tmp; 1291 Uint8 *row1 = (Uint8 *)dst; 1292 Uint8 *row2 = row1 + UVheight * UVpitch; 1293 1294 // Allocate a temporary row for the swap 1295 tmp = (Uint8 *)SDL_malloc(UVwidth); 1296 if (!tmp) { 1297 return false; 1298 } 1299 for (y = 0; y < UVheight; ++y) { 1300 SDL_memcpy(tmp, row1, UVwidth); 1301 SDL_memcpy(row1, row2, UVwidth); 1302 SDL_memcpy(row2, tmp, UVwidth); 1303 row1 += UVpitch; 1304 row2 += UVpitch; 1305 } 1306 SDL_free(tmp); 1307 } else { 1308 const Uint8 *srcUV; 1309 Uint8 *dstUV; 1310 int srcUVPitch = ((src_pitch + 1) / 2); 1311 int dstUVPitch = ((dst_pitch + 1) / 2); 1312 1313 // Copy the first plane 1314 srcUV = (const Uint8 *)src; 1315 dstUV = (Uint8 *)dst + UVheight * dstUVPitch; 1316 for (y = 0; y < UVheight; ++y) { 1317 SDL_memcpy(dstUV, srcUV, UVwidth); 1318 srcUV += srcUVPitch; 1319 dstUV += dstUVPitch; 1320 } 1321 1322 // Copy the second plane 1323 dstUV = (Uint8 *)dst; 1324 for (y = 0; y < UVheight; ++y) { 1325 SDL_memcpy(dstUV, srcUV, UVwidth); 1326 srcUV += srcUVPitch; 1327 dstUV += dstUVPitch; 1328 } 1329 } 1330 return true; 1331} 1332 1333#ifdef SDL_SSE2_INTRINSICS 1334static 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) 1335{ 1336 int x, y; 1337 const int UVwidth = (width + 1) / 2; 1338 const int UVheight = (height + 1) / 2; 1339 const int srcUVPitch = ((src_pitch + 1) / 2); 1340 const int srcUVPitchLeft = srcUVPitch - UVwidth; 1341 const int dstUVPitch = ((dst_pitch + 1) / 2) * 2; 1342 const int dstUVPitchLeft = dstUVPitch - UVwidth * 2; 1343 const Uint8 *src1, *src2; 1344 Uint8 *dstUV; 1345 Uint8 *tmp = NULL; 1346 1347 // Skip the Y plane 1348 src = (const Uint8 *)src + height * src_pitch; 1349 dst = (Uint8 *)dst + height * dst_pitch; 1350 1351 if (src == dst) { 1352 // Need to make a copy of the buffer so we don't clobber it while converting 1353 tmp = (Uint8 *)SDL_malloc((size_t)2 * UVheight * srcUVPitch); 1354 if (tmp == NULL) { 1355 return false; 1356 } 1357 SDL_memcpy(tmp, src, (size_t)2 * UVheight * srcUVPitch); 1358 src = tmp; 1359 } 1360 1361 if (reverseUV) { 1362 src2 = (const Uint8 *)src; 1363 src1 = src2 + UVheight * srcUVPitch; 1364 } else { 1365 src1 = (const Uint8 *)src; 1366 src2 = src1 + UVheight * srcUVPitch; 1367 } 1368 dstUV = (Uint8 *)dst; 1369 1370 y = UVheight; 1371 while (y--) { 1372 x = UVwidth; 1373 while (x >= 16) { 1374 __m128i u = _mm_loadu_si128((__m128i *)src1); 1375 __m128i v = _mm_loadu_si128((__m128i *)src2); 1376 __m128i uv1 = _mm_unpacklo_epi8(u, v); 1377 __m128i uv2 = _mm_unpackhi_epi8(u, v); 1378 _mm_storeu_si128((__m128i *)dstUV, uv1); 1379 _mm_storeu_si128((__m128i *)(dstUV + 16), uv2); 1380 src1 += 16; 1381 src2 += 16; 1382 dstUV += 32; 1383 x -= 16; 1384 } 1385 while (x--) { 1386 *dstUV++ = *src1++; 1387 *dstUV++ = *src2++; 1388 } 1389 src1 += srcUVPitchLeft; 1390 src2 += srcUVPitchLeft; 1391 dstUV += dstUVPitchLeft; 1392 } 1393 1394 if (tmp) { 1395 SDL_free(tmp); 1396 } 1397 return true; 1398} 1399 1400static 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) 1401{ 1402 int x, y; 1403 const int UVwidth = (width + 1) / 2; 1404 const int UVheight = (height + 1) / 2; 1405 const int srcUVPitch = ((src_pitch + 1) / 2) * 2; 1406 const int srcUVPitchLeft = srcUVPitch - UVwidth * 2; 1407 const int dstUVPitch = ((dst_pitch + 1) / 2); 1408 const int dstUVPitchLeft = dstUVPitch - UVwidth; 1409 const Uint8 *srcUV; 1410 Uint8 *dst1, *dst2; 1411 Uint8 *tmp = NULL; 1412 1413 // Skip the Y plane 1414 src = (const Uint8 *)src + height * src_pitch; 1415 dst = (Uint8 *)dst + height * dst_pitch; 1416 1417 if (src == dst) { 1418 // Need to make a copy of the buffer so we don't clobber it while converting 1419 tmp = (Uint8 *)SDL_malloc((size_t)UVheight * srcUVPitch); 1420 if (tmp == NULL) { 1421 return false; 1422 } 1423 SDL_memcpy(tmp, src, (size_t)UVheight * srcUVPitch); 1424 src = tmp; 1425 } 1426 1427 if (reverseUV) { 1428 dst2 = (Uint8 *)dst; 1429 dst1 = dst2 + UVheight * dstUVPitch; 1430 } else { 1431 dst1 = (Uint8 *)dst; 1432 dst2 = dst1 + UVheight * dstUVPitch; 1433 } 1434 srcUV = (const Uint8 *)src; 1435 1436 y = UVheight; 1437 while (y--) { 1438 __m128i mask = _mm_set1_epi16(0x00FF); 1439 x = UVwidth; 1440 while (x >= 16) { 1441 __m128i uv1 = _mm_loadu_si128((__m128i *)srcUV); 1442 __m128i uv2 = _mm_loadu_si128((__m128i *)(srcUV + 16)); 1443 __m128i u1 = _mm_and_si128(uv1, mask); 1444 __m128i u2 = _mm_and_si128(uv2, mask); 1445 __m128i u = _mm_packus_epi16(u1, u2); 1446 __m128i v1 = _mm_srli_epi16(uv1, 8); 1447 __m128i v2 = _mm_srli_epi16(uv2, 8); 1448 __m128i v = _mm_packus_epi16(v1, v2); 1449 _mm_storeu_si128((__m128i *)dst1, u); 1450 _mm_storeu_si128((__m128i *)dst2, v); 1451 srcUV += 32; 1452 dst1 += 16; 1453 dst2 += 16; 1454 x -= 16; 1455 } 1456 while (x--) { 1457 *dst1++ = *srcUV++; 1458 *dst2++ = *srcUV++; 1459 } 1460 srcUV += srcUVPitchLeft; 1461 dst1 += dstUVPitchLeft; 1462 dst2 += dstUVPitchLeft; 1463 } 1464 1465 if (tmp) { 1466 SDL_free(tmp); 1467 } 1468 return true; 1469} 1470 1471static bool SDL_TARGETING("sse2") SDL_ConvertPixels_SwapNV_SSE2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 1472{ 1473 int x, y; 1474 const int UVwidth = (width + 1) / 2; 1475 const int UVheight = (height + 1) / 2; 1476 const int srcUVPitch = ((src_pitch + 1) / 2) * 2; 1477 const int srcUVPitchLeft = (srcUVPitch - UVwidth * 2) / sizeof(Uint16); 1478 const int dstUVPitch = ((dst_pitch + 1) / 2) * 2; 1479 const int dstUVPitchLeft = (dstUVPitch - UVwidth * 2) / sizeof(Uint16); 1480 const Uint16 *srcUV; 1481 Uint16 *dstUV; 1482 1483 // Skip the Y plane 1484 src = (const Uint8 *)src + height * src_pitch; 1485 dst = (Uint8 *)dst + height * dst_pitch; 1486 1487 srcUV = (const Uint16 *)src; 1488 dstUV = (Uint16 *)dst; 1489 y = UVheight; 1490 while (y--) { 1491 x = UVwidth; 1492 while (x >= 8) { 1493 __m128i uv = _mm_loadu_si128((__m128i *)srcUV); 1494 __m128i v = _mm_slli_epi16(uv, 8); 1495 __m128i u = _mm_srli_epi16(uv, 8); 1496 __m128i vu = _mm_or_si128(v, u); 1497 _mm_storeu_si128((__m128i *)dstUV, vu); 1498 srcUV += 8; 1499 dstUV += 8; 1500 x -= 8; 1501 } 1502 if (x > 0) { 1503 const Uint8 *srcUV8 = (const Uint8 *)srcUV; 1504 Uint8 *dstUV8 = (Uint8 *)dstUV; 1505 srcUV += x; 1506 dstUV += x; 1507 while (x--) { 1508 Uint8 u = *srcUV8++; 1509 Uint8 v = *srcUV8++; 1510 *dstUV8++ = v; 1511 *dstUV8++ = u; 1512 } 1513 } 1514 srcUV += srcUVPitchLeft; 1515 dstUV += dstUVPitchLeft; 1516 } 1517 return true; 1518} 1519#endif 1520 1521static bool SDL_ConvertPixels_PackUVPlanes_to_NV_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch, bool reverseUV) 1522{ 1523 int x, y; 1524 const int UVwidth = (width + 1) / 2; 1525 const int UVheight = (height + 1) / 2; 1526 const int srcUVPitch = ((src_pitch + 1) / 2); 1527 const int srcUVPitchLeft = srcUVPitch - UVwidth; 1528 const int dstUVPitch = ((dst_pitch + 1) / 2) * 2; 1529 const int dstUVPitchLeft = dstUVPitch - UVwidth * 2; 1530 const Uint8 *src1, *src2; 1531 Uint8 *dstUV; 1532 Uint8 *tmp = NULL; 1533 1534 // Skip the Y plane 1535 src = (const Uint8 *)src + height * src_pitch; 1536 dst = (Uint8 *)dst + height * dst_pitch; 1537 1538 if (src == dst) { 1539 // Need to make a copy of the buffer so we don't clobber it while converting 1540 tmp = (Uint8 *)SDL_malloc((size_t)2 * UVheight * srcUVPitch); 1541 if (!tmp) { 1542 return false; 1543 } 1544 SDL_memcpy(tmp, src, (size_t)2 * UVheight * srcUVPitch); 1545 src = tmp; 1546 } 1547 1548 if (reverseUV) { 1549 src2 = (const Uint8 *)src; 1550 src1 = src2 + UVheight * srcUVPitch; 1551 } else { 1552 src1 = (const Uint8 *)src; 1553 src2 = src1 + UVheight * srcUVPitch; 1554 } 1555 dstUV = (Uint8 *)dst; 1556 1557 y = UVheight; 1558 while (y--) { 1559 x = UVwidth; 1560 while (x--) { 1561 *dstUV++ = *src1++; 1562 *dstUV++ = *src2++; 1563 } 1564 src1 += srcUVPitchLeft; 1565 src2 += srcUVPitchLeft; 1566 dstUV += dstUVPitchLeft; 1567 } 1568 1569 SDL_free(tmp); 1570 return true; 1571} 1572 1573static bool SDL_ConvertPixels_SplitNV_to_UVPlanes_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch, bool reverseUV) 1574{ 1575 int x, y; 1576 const int UVwidth = (width + 1) / 2; 1577 const int UVheight = (height + 1) / 2; 1578 const int srcUVPitch = ((src_pitch + 1) / 2) * 2; 1579 const int srcUVPitchLeft = srcUVPitch - UVwidth * 2; 1580 const int dstUVPitch = ((dst_pitch + 1) / 2); 1581 const int dstUVPitchLeft = dstUVPitch - UVwidth; 1582 const Uint8 *srcUV; 1583 Uint8 *dst1, *dst2; 1584 Uint8 *tmp = NULL; 1585 1586 // Skip the Y plane 1587 src = (const Uint8 *)src + height * src_pitch; 1588 dst = (Uint8 *)dst + height * dst_pitch; 1589 1590 if (src == dst) { 1591 // Need to make a copy of the buffer so we don't clobber it while converting 1592 tmp = (Uint8 *)SDL_malloc((size_t)UVheight * srcUVPitch); 1593 if (!tmp) { 1594 return false; 1595 } 1596 SDL_memcpy(tmp, src, (size_t)UVheight * srcUVPitch); 1597 src = tmp; 1598 } 1599 1600 if (reverseUV) { 1601 dst2 = (Uint8 *)dst; 1602 dst1 = dst2 + UVheight * dstUVPitch; 1603 } else { 1604 dst1 = (Uint8 *)dst; 1605 dst2 = dst1 + UVheight * dstUVPitch; 1606 } 1607 srcUV = (const Uint8 *)src; 1608 1609 y = UVheight; 1610 while (y--) { 1611 x = UVwidth; 1612 while (x--) { 1613 *dst1++ = *srcUV++; 1614 *dst2++ = *srcUV++; 1615 } 1616 srcUV += srcUVPitchLeft; 1617 dst1 += dstUVPitchLeft; 1618 dst2 += dstUVPitchLeft; 1619 } 1620 1621 SDL_free(tmp); 1622 return true; 1623} 1624 1625static 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 1673static 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 1683static 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 1693static 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 1703static 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 1792static 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 1827static 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 1862static 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 1897static 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 1932static 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 1967static 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 2003static 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 2036static 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 2069static 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 2102static 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 2135static 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 2168static 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 2201static 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 2211static 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 2221static 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 2231static 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 2241static 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 2251static 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 2261static 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 2303static 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 2445static 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 2578bool 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
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.