Atlas - SDL_yuv.c
Home / ext / SDL / src / video Lines: 1 | Size: 90534 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 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 while (x--) { 1503 *dstUV++ = SDL_Swap16(*srcUV++); 1504 } 1505 srcUV += srcUVPitchLeft; 1506 dstUV += dstUVPitchLeft; 1507 } 1508 return true; 1509} 1510#endif 1511 1512static bool SDL_ConvertPixels_PackUVPlanes_to_NV_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch, bool reverseUV) 1513{ 1514 int x, y; 1515 const int UVwidth = (width + 1) / 2; 1516 const int UVheight = (height + 1) / 2; 1517 const int srcUVPitch = ((src_pitch + 1) / 2); 1518 const int srcUVPitchLeft = srcUVPitch - UVwidth; 1519 const int dstUVPitch = ((dst_pitch + 1) / 2) * 2; 1520 const int dstUVPitchLeft = dstUVPitch - UVwidth * 2; 1521 const Uint8 *src1, *src2; 1522 Uint8 *dstUV; 1523 Uint8 *tmp = NULL; 1524 1525 // Skip the Y plane 1526 src = (const Uint8 *)src + height * src_pitch; 1527 dst = (Uint8 *)dst + height * dst_pitch; 1528 1529 if (src == dst) { 1530 // Need to make a copy of the buffer so we don't clobber it while converting 1531 tmp = (Uint8 *)SDL_malloc((size_t)2 * UVheight * srcUVPitch); 1532 if (!tmp) { 1533 return false; 1534 } 1535 SDL_memcpy(tmp, src, (size_t)2 * UVheight * srcUVPitch); 1536 src = tmp; 1537 } 1538 1539 if (reverseUV) { 1540 src2 = (const Uint8 *)src; 1541 src1 = src2 + UVheight * srcUVPitch; 1542 } else { 1543 src1 = (const Uint8 *)src; 1544 src2 = src1 + UVheight * srcUVPitch; 1545 } 1546 dstUV = (Uint8 *)dst; 1547 1548 y = UVheight; 1549 while (y--) { 1550 x = UVwidth; 1551 while (x--) { 1552 *dstUV++ = *src1++; 1553 *dstUV++ = *src2++; 1554 } 1555 src1 += srcUVPitchLeft; 1556 src2 += srcUVPitchLeft; 1557 dstUV += dstUVPitchLeft; 1558 } 1559 1560 SDL_free(tmp); 1561 return true; 1562} 1563 1564static bool SDL_ConvertPixels_SplitNV_to_UVPlanes_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch, bool reverseUV) 1565{ 1566 int x, y; 1567 const int UVwidth = (width + 1) / 2; 1568 const int UVheight = (height + 1) / 2; 1569 const int srcUVPitch = ((src_pitch + 1) / 2) * 2; 1570 const int srcUVPitchLeft = srcUVPitch - UVwidth * 2; 1571 const int dstUVPitch = ((dst_pitch + 1) / 2); 1572 const int dstUVPitchLeft = dstUVPitch - UVwidth; 1573 const Uint8 *srcUV; 1574 Uint8 *dst1, *dst2; 1575 Uint8 *tmp = NULL; 1576 1577 // Skip the Y plane 1578 src = (const Uint8 *)src + height * src_pitch; 1579 dst = (Uint8 *)dst + height * dst_pitch; 1580 1581 if (src == dst) { 1582 // Need to make a copy of the buffer so we don't clobber it while converting 1583 tmp = (Uint8 *)SDL_malloc((size_t)UVheight * srcUVPitch); 1584 if (!tmp) { 1585 return false; 1586 } 1587 SDL_memcpy(tmp, src, (size_t)UVheight * srcUVPitch); 1588 src = tmp; 1589 } 1590 1591 if (reverseUV) { 1592 dst2 = (Uint8 *)dst; 1593 dst1 = dst2 + UVheight * dstUVPitch; 1594 } else { 1595 dst1 = (Uint8 *)dst; 1596 dst2 = dst1 + UVheight * dstUVPitch; 1597 } 1598 srcUV = (const Uint8 *)src; 1599 1600 y = UVheight; 1601 while (y--) { 1602 x = UVwidth; 1603 while (x--) { 1604 *dst1++ = *srcUV++; 1605 *dst2++ = *srcUV++; 1606 } 1607 srcUV += srcUVPitchLeft; 1608 dst1 += dstUVPitchLeft; 1609 dst2 += dstUVPitchLeft; 1610 } 1611 1612 SDL_free(tmp); 1613 return true; 1614} 1615 1616static bool SDL_ConvertPixels_SwapNV_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 1617{ 1618 int x, y; 1619 const int UVwidth = (width + 1) / 2; 1620 const int UVheight = (height + 1) / 2; 1621 const int srcUVPitch = ((src_pitch + 1) / 2) * 2; 1622 const int dstUVPitch = ((dst_pitch + 1) / 2) * 2; 1623 1624 // Skip the Y plane 1625 src = (const Uint8 *)src + height * src_pitch; 1626 dst = (Uint8 *)dst + height * dst_pitch; 1627 1628 bool aligned = (((uintptr_t)src | (uintptr_t)dst) & 1) == 0; 1629 if (aligned) { 1630 const int srcUVPitchLeft = (srcUVPitch - UVwidth * 2) / sizeof(Uint16); 1631 const int dstUVPitchLeft = (dstUVPitch - UVwidth * 2) / sizeof(Uint16); 1632 const Uint16 *srcUV = (const Uint16 *)src; 1633 Uint16 *dstUV = (Uint16 *)dst; 1634 y = UVheight; 1635 while (y--) { 1636 x = UVwidth; 1637 while (x--) { 1638 *dstUV++ = SDL_Swap16(*srcUV++); 1639 } 1640 srcUV += srcUVPitchLeft; 1641 dstUV += dstUVPitchLeft; 1642 } 1643 } else { 1644 const int srcUVPitchLeft = (srcUVPitch - UVwidth * 2); 1645 const int dstUVPitchLeft = (dstUVPitch - UVwidth * 2); 1646 const Uint8 *srcUV = (const Uint8 *)src; 1647 Uint8 *dstUV = (Uint8 *)dst; 1648 y = UVheight; 1649 while (y--) { 1650 x = UVwidth; 1651 while (x--) { 1652 Uint8 u = *srcUV++; 1653 Uint8 v = *srcUV++; 1654 *dstUV++ = v; 1655 *dstUV++ = u; 1656 } 1657 srcUV += srcUVPitchLeft; 1658 dstUV += dstUVPitchLeft; 1659 } 1660 } 1661 return true; 1662} 1663 1664static bool SDL_ConvertPixels_PackUVPlanes_to_NV(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch, bool reverseUV) 1665{ 1666#ifdef SDL_SSE2_INTRINSICS 1667 if (SDL_HasSSE2()) { 1668 return SDL_ConvertPixels_PackUVPlanes_to_NV_SSE2(width, height, src, src_pitch, dst, dst_pitch, reverseUV); 1669 } 1670#endif 1671 return SDL_ConvertPixels_PackUVPlanes_to_NV_std(width, height, src, src_pitch, dst, dst_pitch, reverseUV); 1672} 1673 1674static bool SDL_ConvertPixels_SplitNV_to_UVPlanes(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch, bool reverseUV) 1675{ 1676#ifdef SDL_SSE2_INTRINSICS 1677 if (SDL_HasSSE2()) { 1678 return SDL_ConvertPixels_SplitNV_to_UVPlanes_SSE2(width, height, src, src_pitch, dst, dst_pitch, reverseUV); 1679 } 1680#endif 1681 return SDL_ConvertPixels_SplitNV_to_UVPlanes_std(width, height, src, src_pitch, dst, dst_pitch, reverseUV); 1682} 1683 1684static bool SDL_ConvertPixels_SwapNV(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 1685{ 1686#ifdef SDL_SSE2_INTRINSICS 1687 if (SDL_HasSSE2()) { 1688 return SDL_ConvertPixels_SwapNV_SSE2(width, height, src, src_pitch, dst, dst_pitch); 1689 } 1690#endif 1691 return SDL_ConvertPixels_SwapNV_std(width, height, src, src_pitch, dst, dst_pitch); 1692} 1693 1694static bool SDL_ConvertPixels_Planar2x2_to_Planar2x2(int width, int height, 1695 SDL_PixelFormat src_format, const void *src, int src_pitch, 1696 SDL_PixelFormat dst_format, void *dst, int dst_pitch) 1697{ 1698 if (src != dst) { 1699 // Copy Y plane 1700 int i; 1701 const Uint8 *srcY = (const Uint8 *)src; 1702 Uint8 *dstY = (Uint8 *)dst; 1703 for (i = height; i--;) { 1704 SDL_memcpy(dstY, srcY, width); 1705 srcY += src_pitch; 1706 dstY += dst_pitch; 1707 } 1708 } 1709 1710 switch (src_format) { 1711 case SDL_PIXELFORMAT_YV12: 1712 switch (dst_format) { 1713 case SDL_PIXELFORMAT_IYUV: 1714 return SDL_ConvertPixels_SwapUVPlanes(width, height, src, src_pitch, dst, dst_pitch); 1715 case SDL_PIXELFORMAT_NV12: 1716 return SDL_ConvertPixels_PackUVPlanes_to_NV(width, height, src, src_pitch, dst, dst_pitch, true); 1717 case SDL_PIXELFORMAT_NV21: 1718 return SDL_ConvertPixels_PackUVPlanes_to_NV(width, height, src, src_pitch, dst, dst_pitch, false); 1719 default: 1720 break; 1721 } 1722 break; 1723 case SDL_PIXELFORMAT_IYUV: 1724 switch (dst_format) { 1725 case SDL_PIXELFORMAT_YV12: 1726 return SDL_ConvertPixels_SwapUVPlanes(width, height, src, src_pitch, dst, dst_pitch); 1727 case SDL_PIXELFORMAT_NV12: 1728 return SDL_ConvertPixels_PackUVPlanes_to_NV(width, height, src, src_pitch, dst, dst_pitch, false); 1729 case SDL_PIXELFORMAT_NV21: 1730 return SDL_ConvertPixels_PackUVPlanes_to_NV(width, height, src, src_pitch, dst, dst_pitch, true); 1731 default: 1732 break; 1733 } 1734 break; 1735 case SDL_PIXELFORMAT_NV12: 1736 switch (dst_format) { 1737 case SDL_PIXELFORMAT_YV12: 1738 return SDL_ConvertPixels_SplitNV_to_UVPlanes(width, height, src, src_pitch, dst, dst_pitch, true); 1739 case SDL_PIXELFORMAT_IYUV: 1740 return SDL_ConvertPixels_SplitNV_to_UVPlanes(width, height, src, src_pitch, dst, dst_pitch, false); 1741 case SDL_PIXELFORMAT_NV21: 1742 return SDL_ConvertPixels_SwapNV(width, height, src, src_pitch, dst, dst_pitch); 1743 default: 1744 break; 1745 } 1746 break; 1747 case SDL_PIXELFORMAT_NV21: 1748 switch (dst_format) { 1749 case SDL_PIXELFORMAT_YV12: 1750 return SDL_ConvertPixels_SplitNV_to_UVPlanes(width, height, src, src_pitch, dst, dst_pitch, false); 1751 case SDL_PIXELFORMAT_IYUV: 1752 return SDL_ConvertPixels_SplitNV_to_UVPlanes(width, height, src, src_pitch, dst, dst_pitch, true); 1753 case SDL_PIXELFORMAT_NV12: 1754 return SDL_ConvertPixels_SwapNV(width, height, src, src_pitch, dst, dst_pitch); 1755 default: 1756 break; 1757 } 1758 break; 1759 default: 1760 break; 1761 } 1762 return SDL_SetError("SDL_ConvertPixels_Planar2x2_to_Planar2x2: Unsupported YUV conversion: %s -> %s", SDL_GetPixelFormatName(src_format), 1763 SDL_GetPixelFormatName(dst_format)); 1764} 1765 1766#ifdef SDL_SSE2_INTRINSICS 1767#define PACKED4_TO_PACKED4_ROW_SSE2(shuffle) \ 1768 while (x >= 4) { \ 1769 __m128i yuv = _mm_loadu_si128((__m128i *)srcYUV); \ 1770 __m128i lo = _mm_unpacklo_epi8(yuv, _mm_setzero_si128()); \ 1771 __m128i hi = _mm_unpackhi_epi8(yuv, _mm_setzero_si128()); \ 1772 lo = _mm_shufflelo_epi16(lo, shuffle); \ 1773 lo = _mm_shufflehi_epi16(lo, shuffle); \ 1774 hi = _mm_shufflelo_epi16(hi, shuffle); \ 1775 hi = _mm_shufflehi_epi16(hi, shuffle); \ 1776 yuv = _mm_packus_epi16(lo, hi); \ 1777 _mm_storeu_si128((__m128i *)dstYUV, yuv); \ 1778 srcYUV += 16; \ 1779 dstYUV += 16; \ 1780 x -= 4; \ 1781 } 1782 1783static 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) 1784{ 1785 int x, y; 1786 const int YUVwidth = (width + 1) / 2; 1787 const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); 1788 const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); 1789 const Uint8 *srcYUV = (const Uint8 *)src; 1790 Uint8 *dstYUV = (Uint8 *)dst; 1791 1792 y = height; 1793 x = YUVwidth; 1794 while (y--) { 1795 PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(2, 3, 0, 1)); 1796 while (x--) { 1797 Uint8 Y1, U, Y2, V; 1798 1799 Y1 = srcYUV[0]; 1800 U = srcYUV[1]; 1801 Y2 = srcYUV[2]; 1802 V = srcYUV[3]; 1803 srcYUV += 4; 1804 1805 dstYUV[0] = U; 1806 dstYUV[1] = Y1; 1807 dstYUV[2] = V; 1808 dstYUV[3] = Y2; 1809 dstYUV += 4; 1810 } 1811 srcYUV += srcYUVPitchLeft; 1812 dstYUV += dstYUVPitchLeft; 1813 x = YUVwidth; 1814 } 1815 return true; 1816} 1817 1818static 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) 1819{ 1820 int x, y; 1821 const int YUVwidth = (width + 1) / 2; 1822 const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); 1823 const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); 1824 const Uint8 *srcYUV = (const Uint8 *)src; 1825 Uint8 *dstYUV = (Uint8 *)dst; 1826 1827 y = height; 1828 x = YUVwidth; 1829 while (y--) { 1830 PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(1, 2, 3, 0)); 1831 while (x--) { 1832 Uint8 Y1, U, Y2, V; 1833 1834 Y1 = srcYUV[0]; 1835 U = srcYUV[1]; 1836 Y2 = srcYUV[2]; 1837 V = srcYUV[3]; 1838 srcYUV += 4; 1839 1840 dstYUV[0] = Y1; 1841 dstYUV[1] = V; 1842 dstYUV[2] = Y2; 1843 dstYUV[3] = U; 1844 dstYUV += 4; 1845 } 1846 srcYUV += srcYUVPitchLeft; 1847 dstYUV += dstYUVPitchLeft; 1848 x = YUVwidth; 1849 } 1850 return true; 1851} 1852 1853static 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) 1854{ 1855 int x, y; 1856 const int YUVwidth = (width + 1) / 2; 1857 const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); 1858 const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); 1859 const Uint8 *srcYUV = (const Uint8 *)src; 1860 Uint8 *dstYUV = (Uint8 *)dst; 1861 1862 y = height; 1863 x = YUVwidth; 1864 while (y--) { 1865 PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(2, 3, 0, 1)); 1866 while (x--) { 1867 Uint8 Y1, U, Y2, V; 1868 1869 U = srcYUV[0]; 1870 Y1 = srcYUV[1]; 1871 V = srcYUV[2]; 1872 Y2 = srcYUV[3]; 1873 srcYUV += 4; 1874 1875 dstYUV[0] = Y1; 1876 dstYUV[1] = U; 1877 dstYUV[2] = Y2; 1878 dstYUV[3] = V; 1879 dstYUV += 4; 1880 } 1881 srcYUV += srcYUVPitchLeft; 1882 dstYUV += dstYUVPitchLeft; 1883 x = YUVwidth; 1884 } 1885 return true; 1886} 1887 1888static 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) 1889{ 1890 int x, y; 1891 const int YUVwidth = (width + 1) / 2; 1892 const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); 1893 const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); 1894 const Uint8 *srcYUV = (const Uint8 *)src; 1895 Uint8 *dstYUV = (Uint8 *)dst; 1896 1897 y = height; 1898 x = YUVwidth; 1899 while (y--) { 1900 PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(0, 3, 2, 1)); 1901 while (x--) { 1902 Uint8 Y1, U, Y2, V; 1903 1904 U = srcYUV[0]; 1905 Y1 = srcYUV[1]; 1906 V = srcYUV[2]; 1907 Y2 = srcYUV[3]; 1908 srcYUV += 4; 1909 1910 dstYUV[0] = Y1; 1911 dstYUV[1] = V; 1912 dstYUV[2] = Y2; 1913 dstYUV[3] = U; 1914 dstYUV += 4; 1915 } 1916 srcYUV += srcYUVPitchLeft; 1917 dstYUV += dstYUVPitchLeft; 1918 x = YUVwidth; 1919 } 1920 return true; 1921} 1922 1923static 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) 1924{ 1925 int x, y; 1926 const int YUVwidth = (width + 1) / 2; 1927 const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); 1928 const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); 1929 const Uint8 *srcYUV = (const Uint8 *)src; 1930 Uint8 *dstYUV = (Uint8 *)dst; 1931 1932 y = height; 1933 x = YUVwidth; 1934 while (y--) { 1935 PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(1, 2, 3, 0)); 1936 while (x--) { 1937 Uint8 Y1, U, Y2, V; 1938 1939 Y1 = srcYUV[0]; 1940 V = srcYUV[1]; 1941 Y2 = srcYUV[2]; 1942 U = srcYUV[3]; 1943 srcYUV += 4; 1944 1945 dstYUV[0] = Y1; 1946 dstYUV[1] = U; 1947 dstYUV[2] = Y2; 1948 dstYUV[3] = V; 1949 dstYUV += 4; 1950 } 1951 srcYUV += srcYUVPitchLeft; 1952 dstYUV += dstYUVPitchLeft; 1953 x = YUVwidth; 1954 } 1955 return true; 1956} 1957 1958static 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) 1959{ 1960 int x, y; 1961 const int YUVwidth = (width + 1) / 2; 1962 const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); 1963 const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); 1964 const Uint8 *srcYUV = (const Uint8 *)src; 1965 Uint8 *dstYUV = (Uint8 *)dst; 1966 1967 y = height; 1968 x = YUVwidth; 1969 while (y--) { 1970 PACKED4_TO_PACKED4_ROW_SSE2(_MM_SHUFFLE(2, 1, 0, 3)); 1971 while (x--) { 1972 Uint8 Y1, U, Y2, V; 1973 1974 Y1 = srcYUV[0]; 1975 V = srcYUV[1]; 1976 Y2 = srcYUV[2]; 1977 U = srcYUV[3]; 1978 srcYUV += 4; 1979 1980 dstYUV[0] = U; 1981 dstYUV[1] = Y1; 1982 dstYUV[2] = V; 1983 dstYUV[3] = Y2; 1984 dstYUV += 4; 1985 } 1986 srcYUV += srcYUVPitchLeft; 1987 dstYUV += dstYUVPitchLeft; 1988 x = YUVwidth; 1989 } 1990 return true; 1991} 1992#endif 1993 1994static bool SDL_ConvertPixels_YUY2_to_UYVY_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 1995{ 1996 int x, y; 1997 const int YUVwidth = (width + 1) / 2; 1998 const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); 1999 const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); 2000 const Uint8 *srcYUV = (const Uint8 *)src; 2001 Uint8 *dstYUV = (Uint8 *)dst; 2002 2003 y = height; 2004 while (y--) { 2005 x = YUVwidth; 2006 while (x--) { 2007 Uint8 Y1, U, Y2, V; 2008 2009 Y1 = srcYUV[0]; 2010 U = srcYUV[1]; 2011 Y2 = srcYUV[2]; 2012 V = srcYUV[3]; 2013 srcYUV += 4; 2014 2015 dstYUV[0] = U; 2016 dstYUV[1] = Y1; 2017 dstYUV[2] = V; 2018 dstYUV[3] = Y2; 2019 dstYUV += 4; 2020 } 2021 srcYUV += srcYUVPitchLeft; 2022 dstYUV += dstYUVPitchLeft; 2023 } 2024 return true; 2025} 2026 2027static bool SDL_ConvertPixels_YUY2_to_YVYU_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 2028{ 2029 int x, y; 2030 const int YUVwidth = (width + 1) / 2; 2031 const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); 2032 const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); 2033 const Uint8 *srcYUV = (const Uint8 *)src; 2034 Uint8 *dstYUV = (Uint8 *)dst; 2035 2036 y = height; 2037 while (y--) { 2038 x = YUVwidth; 2039 while (x--) { 2040 Uint8 Y1, U, Y2, V; 2041 2042 Y1 = srcYUV[0]; 2043 U = srcYUV[1]; 2044 Y2 = srcYUV[2]; 2045 V = srcYUV[3]; 2046 srcYUV += 4; 2047 2048 dstYUV[0] = Y1; 2049 dstYUV[1] = V; 2050 dstYUV[2] = Y2; 2051 dstYUV[3] = U; 2052 dstYUV += 4; 2053 } 2054 srcYUV += srcYUVPitchLeft; 2055 dstYUV += dstYUVPitchLeft; 2056 } 2057 return true; 2058} 2059 2060static bool SDL_ConvertPixels_UYVY_to_YUY2_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 2061{ 2062 int x, y; 2063 const int YUVwidth = (width + 1) / 2; 2064 const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); 2065 const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); 2066 const Uint8 *srcYUV = (const Uint8 *)src; 2067 Uint8 *dstYUV = (Uint8 *)dst; 2068 2069 y = height; 2070 while (y--) { 2071 x = YUVwidth; 2072 while (x--) { 2073 Uint8 Y1, U, Y2, V; 2074 2075 U = srcYUV[0]; 2076 Y1 = srcYUV[1]; 2077 V = srcYUV[2]; 2078 Y2 = srcYUV[3]; 2079 srcYUV += 4; 2080 2081 dstYUV[0] = Y1; 2082 dstYUV[1] = U; 2083 dstYUV[2] = Y2; 2084 dstYUV[3] = V; 2085 dstYUV += 4; 2086 } 2087 srcYUV += srcYUVPitchLeft; 2088 dstYUV += dstYUVPitchLeft; 2089 } 2090 return true; 2091} 2092 2093static bool SDL_ConvertPixels_UYVY_to_YVYU_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 2094{ 2095 int x, y; 2096 const int YUVwidth = (width + 1) / 2; 2097 const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); 2098 const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); 2099 const Uint8 *srcYUV = (const Uint8 *)src; 2100 Uint8 *dstYUV = (Uint8 *)dst; 2101 2102 y = height; 2103 while (y--) { 2104 x = YUVwidth; 2105 while (x--) { 2106 Uint8 Y1, U, Y2, V; 2107 2108 U = srcYUV[0]; 2109 Y1 = srcYUV[1]; 2110 V = srcYUV[2]; 2111 Y2 = srcYUV[3]; 2112 srcYUV += 4; 2113 2114 dstYUV[0] = Y1; 2115 dstYUV[1] = V; 2116 dstYUV[2] = Y2; 2117 dstYUV[3] = U; 2118 dstYUV += 4; 2119 } 2120 srcYUV += srcYUVPitchLeft; 2121 dstYUV += dstYUVPitchLeft; 2122 } 2123 return true; 2124} 2125 2126static bool SDL_ConvertPixels_YVYU_to_YUY2_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 2127{ 2128 int x, y; 2129 const int YUVwidth = (width + 1) / 2; 2130 const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); 2131 const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); 2132 const Uint8 *srcYUV = (const Uint8 *)src; 2133 Uint8 *dstYUV = (Uint8 *)dst; 2134 2135 y = height; 2136 while (y--) { 2137 x = YUVwidth; 2138 while (x--) { 2139 Uint8 Y1, U, Y2, V; 2140 2141 Y1 = srcYUV[0]; 2142 V = srcYUV[1]; 2143 Y2 = srcYUV[2]; 2144 U = srcYUV[3]; 2145 srcYUV += 4; 2146 2147 dstYUV[0] = Y1; 2148 dstYUV[1] = U; 2149 dstYUV[2] = Y2; 2150 dstYUV[3] = V; 2151 dstYUV += 4; 2152 } 2153 srcYUV += srcYUVPitchLeft; 2154 dstYUV += dstYUVPitchLeft; 2155 } 2156 return true; 2157} 2158 2159static bool SDL_ConvertPixels_YVYU_to_UYVY_std(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 2160{ 2161 int x, y; 2162 const int YUVwidth = (width + 1) / 2; 2163 const int srcYUVPitchLeft = (src_pitch - YUVwidth * 4); 2164 const int dstYUVPitchLeft = (dst_pitch - YUVwidth * 4); 2165 const Uint8 *srcYUV = (const Uint8 *)src; 2166 Uint8 *dstYUV = (Uint8 *)dst; 2167 2168 y = height; 2169 while (y--) { 2170 x = YUVwidth; 2171 while (x--) { 2172 Uint8 Y1, U, Y2, V; 2173 2174 Y1 = srcYUV[0]; 2175 V = srcYUV[1]; 2176 Y2 = srcYUV[2]; 2177 U = srcYUV[3]; 2178 srcYUV += 4; 2179 2180 dstYUV[0] = U; 2181 dstYUV[1] = Y1; 2182 dstYUV[2] = V; 2183 dstYUV[3] = Y2; 2184 dstYUV += 4; 2185 } 2186 srcYUV += srcYUVPitchLeft; 2187 dstYUV += dstYUVPitchLeft; 2188 } 2189 return true; 2190} 2191 2192static bool SDL_ConvertPixels_YUY2_to_UYVY(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 2193{ 2194#ifdef SDL_SSE2_INTRINSICS 2195 if (SDL_HasSSE2()) { 2196 return SDL_ConvertPixels_YUY2_to_UYVY_SSE2(width, height, src, src_pitch, dst, dst_pitch); 2197 } 2198#endif 2199 return SDL_ConvertPixels_YUY2_to_UYVY_std(width, height, src, src_pitch, dst, dst_pitch); 2200} 2201 2202static bool SDL_ConvertPixels_YUY2_to_YVYU(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 2203{ 2204#ifdef SDL_SSE2_INTRINSICS 2205 if (SDL_HasSSE2()) { 2206 return SDL_ConvertPixels_YUY2_to_YVYU_SSE2(width, height, src, src_pitch, dst, dst_pitch); 2207 } 2208#endif 2209 return SDL_ConvertPixels_YUY2_to_YVYU_std(width, height, src, src_pitch, dst, dst_pitch); 2210} 2211 2212static bool SDL_ConvertPixels_UYVY_to_YUY2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 2213{ 2214#ifdef SDL_SSE2_INTRINSICS 2215 if (SDL_HasSSE2()) { 2216 return SDL_ConvertPixels_UYVY_to_YUY2_SSE2(width, height, src, src_pitch, dst, dst_pitch); 2217 } 2218#endif 2219 return SDL_ConvertPixels_UYVY_to_YUY2_std(width, height, src, src_pitch, dst, dst_pitch); 2220} 2221 2222static bool SDL_ConvertPixels_UYVY_to_YVYU(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 2223{ 2224#ifdef SDL_SSE2_INTRINSICS 2225 if (SDL_HasSSE2()) { 2226 return SDL_ConvertPixels_UYVY_to_YVYU_SSE2(width, height, src, src_pitch, dst, dst_pitch); 2227 } 2228#endif 2229 return SDL_ConvertPixels_UYVY_to_YVYU_std(width, height, src, src_pitch, dst, dst_pitch); 2230} 2231 2232static bool SDL_ConvertPixels_YVYU_to_YUY2(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 2233{ 2234#ifdef SDL_SSE2_INTRINSICS 2235 if (SDL_HasSSE2()) { 2236 return SDL_ConvertPixels_YVYU_to_YUY2_SSE2(width, height, src, src_pitch, dst, dst_pitch); 2237 } 2238#endif 2239 return SDL_ConvertPixels_YVYU_to_YUY2_std(width, height, src, src_pitch, dst, dst_pitch); 2240} 2241 2242static bool SDL_ConvertPixels_YVYU_to_UYVY(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch) 2243{ 2244#ifdef SDL_SSE2_INTRINSICS 2245 if (SDL_HasSSE2()) { 2246 return SDL_ConvertPixels_YVYU_to_UYVY_SSE2(width, height, src, src_pitch, dst, dst_pitch); 2247 } 2248#endif 2249 return SDL_ConvertPixels_YVYU_to_UYVY_std(width, height, src, src_pitch, dst, dst_pitch); 2250} 2251 2252static bool SDL_ConvertPixels_Packed4_to_Packed4(int width, int height, 2253 SDL_PixelFormat src_format, const void *src, int src_pitch, 2254 SDL_PixelFormat dst_format, void *dst, int dst_pitch) 2255{ 2256 switch (src_format) { 2257 case SDL_PIXELFORMAT_YUY2: 2258 switch (dst_format) { 2259 case SDL_PIXELFORMAT_UYVY: 2260 return SDL_ConvertPixels_YUY2_to_UYVY(width, height, src, src_pitch, dst, dst_pitch); 2261 case SDL_PIXELFORMAT_YVYU: 2262 return SDL_ConvertPixels_YUY2_to_YVYU(width, height, src, src_pitch, dst, dst_pitch); 2263 default: 2264 break; 2265 } 2266 break; 2267 case SDL_PIXELFORMAT_UYVY: 2268 switch (dst_format) { 2269 case SDL_PIXELFORMAT_YUY2: 2270 return SDL_ConvertPixels_UYVY_to_YUY2(width, height, src, src_pitch, dst, dst_pitch); 2271 case SDL_PIXELFORMAT_YVYU: 2272 return SDL_ConvertPixels_UYVY_to_YVYU(width, height, src, src_pitch, dst, dst_pitch); 2273 default: 2274 break; 2275 } 2276 break; 2277 case SDL_PIXELFORMAT_YVYU: 2278 switch (dst_format) { 2279 case SDL_PIXELFORMAT_YUY2: 2280 return SDL_ConvertPixels_YVYU_to_YUY2(width, height, src, src_pitch, dst, dst_pitch); 2281 case SDL_PIXELFORMAT_UYVY: 2282 return SDL_ConvertPixels_YVYU_to_UYVY(width, height, src, src_pitch, dst, dst_pitch); 2283 default: 2284 break; 2285 } 2286 break; 2287 default: 2288 break; 2289 } 2290 return SDL_SetError("SDL_ConvertPixels_Packed4_to_Packed4: Unsupported YUV conversion: %s -> %s", SDL_GetPixelFormatName(src_format), 2291 SDL_GetPixelFormatName(dst_format)); 2292} 2293 2294static bool SDL_ConvertPixels_Planar2x2_to_Packed4(int width, int height, 2295 SDL_PixelFormat src_format, const void *src, int src_pitch, 2296 SDL_PixelFormat dst_format, void *dst, int dst_pitch) 2297{ 2298 int x, y; 2299 const Uint8 *srcY1, *srcY2, *srcU, *srcV; 2300 Uint32 srcY_pitch, srcUV_pitch; 2301 Uint32 srcY_pitch_left, srcUV_pitch_left, srcUV_pixel_stride; 2302 Uint8 *dstY1, *dstY2, *dstU1, *dstU2, *dstV1, *dstV2; 2303 Uint32 dstY_pitch, dstUV_pitch; 2304 Uint32 dst_pitch_left; 2305 2306 if (src == dst) { 2307 return SDL_SetError("Can't change YUV plane types in-place"); 2308 } 2309 2310 if (!GetYUVPlanes(width, height, src_format, src, src_pitch, 2311 &srcY1, &srcU, &srcV, &srcY_pitch, &srcUV_pitch)) { 2312 return false; 2313 } 2314 srcY2 = srcY1 + srcY_pitch; 2315 srcY_pitch_left = (srcY_pitch - width); 2316 2317 if (src_format == SDL_PIXELFORMAT_NV12 || src_format == SDL_PIXELFORMAT_NV21) { 2318 srcUV_pixel_stride = 2; 2319 srcUV_pitch_left = (srcUV_pitch - 2 * ((width + 1) / 2)); 2320 } else { 2321 srcUV_pixel_stride = 1; 2322 srcUV_pitch_left = (srcUV_pitch - ((width + 1) / 2)); 2323 } 2324 2325 if (!GetYUVPlanes(width, height, dst_format, dst, dst_pitch, 2326 (const Uint8 **)&dstY1, (const Uint8 **)&dstU1, (const Uint8 **)&dstV1, 2327 &dstY_pitch, &dstUV_pitch)) { 2328 return false; 2329 } 2330 dstY2 = dstY1 + dstY_pitch; 2331 dstU2 = dstU1 + dstUV_pitch; 2332 dstV2 = dstV1 + dstUV_pitch; 2333 dst_pitch_left = (dstY_pitch - 4 * ((width + 1) / 2)); 2334 2335 // Copy 2x2 blocks of pixels at a time 2336 for (y = 0; y < (height - 1); y += 2) { 2337 for (x = 0; x < (width - 1); x += 2) { 2338 // Row 1 2339 *dstY1 = *srcY1++; 2340 dstY1 += 2; 2341 *dstY1 = *srcY1++; 2342 dstY1 += 2; 2343 *dstU1 = *srcU; 2344 *dstV1 = *srcV; 2345 2346 // Row 2 2347 *dstY2 = *srcY2++; 2348 dstY2 += 2; 2349 *dstY2 = *srcY2++; 2350 dstY2 += 2; 2351 *dstU2 = *srcU; 2352 *dstV2 = *srcV; 2353 2354 srcU += srcUV_pixel_stride; 2355 srcV += srcUV_pixel_stride; 2356 dstU1 += 4; 2357 dstU2 += 4; 2358 dstV1 += 4; 2359 dstV2 += 4; 2360 } 2361 2362 // Last column 2363 if (x == (width - 1)) { 2364 // Row 1 2365 *dstY1 = *srcY1; 2366 dstY1 += 2; 2367 *dstY1 = *srcY1++; 2368 dstY1 += 2; 2369 *dstU1 = *srcU; 2370 *dstV1 = *srcV; 2371 2372 // Row 2 2373 *dstY2 = *srcY2; 2374 dstY2 += 2; 2375 *dstY2 = *srcY2++; 2376 dstY2 += 2; 2377 *dstU2 = *srcU; 2378 *dstV2 = *srcV; 2379 2380 srcU += srcUV_pixel_stride; 2381 srcV += srcUV_pixel_stride; 2382 dstU1 += 4; 2383 dstU2 += 4; 2384 dstV1 += 4; 2385 dstV2 += 4; 2386 } 2387 2388 srcY1 += srcY_pitch_left + srcY_pitch; 2389 srcY2 += srcY_pitch_left + srcY_pitch; 2390 srcU += srcUV_pitch_left; 2391 srcV += srcUV_pitch_left; 2392 dstY1 += dst_pitch_left + dstY_pitch; 2393 dstY2 += dst_pitch_left + dstY_pitch; 2394 dstU1 += dst_pitch_left + dstUV_pitch; 2395 dstU2 += dst_pitch_left + dstUV_pitch; 2396 dstV1 += dst_pitch_left + dstUV_pitch; 2397 dstV2 += dst_pitch_left + dstUV_pitch; 2398 } 2399 2400 // Last row 2401 if (y == (height - 1)) { 2402 for (x = 0; x < (width - 1); x += 2) { 2403 // Row 1 2404 *dstY1 = *srcY1++; 2405 dstY1 += 2; 2406 *dstY1 = *srcY1++; 2407 dstY1 += 2; 2408 *dstU1 = *srcU; 2409 *dstV1 = *srcV; 2410 2411 srcU += srcUV_pixel_stride; 2412 srcV += srcUV_pixel_stride; 2413 dstU1 += 4; 2414 dstV1 += 4; 2415 } 2416 2417 // Last column 2418 if (x == (width - 1)) { 2419 // Row 1 2420 *dstY1 = *srcY1; 2421 dstY1 += 2; 2422 *dstY1 = *srcY1++; 2423 dstY1 += 2; 2424 *dstU1 = *srcU; 2425 *dstV1 = *srcV; 2426 2427 srcU += srcUV_pixel_stride; 2428 srcV += srcUV_pixel_stride; 2429 dstU1 += 4; 2430 dstV1 += 4; 2431 } 2432 } 2433 return true; 2434} 2435 2436static bool SDL_ConvertPixels_Packed4_to_Planar2x2(int width, int height, 2437 SDL_PixelFormat src_format, const void *src, int src_pitch, 2438 SDL_PixelFormat dst_format, void *dst, int dst_pitch) 2439{ 2440 int x, y; 2441 const Uint8 *srcY1, *srcY2, *srcU1, *srcU2, *srcV1, *srcV2; 2442 Uint32 srcY_pitch, srcUV_pitch; 2443 Uint32 src_pitch_left; 2444 Uint8 *dstY1, *dstY2, *dstU, *dstV; 2445 Uint32 dstY_pitch, dstUV_pitch; 2446 Uint32 dstY_pitch_left, dstUV_pitch_left, dstUV_pixel_stride; 2447 2448 if (src == dst) { 2449 return SDL_SetError("Can't change YUV plane types in-place"); 2450 } 2451 2452 if (!GetYUVPlanes(width, height, src_format, src, src_pitch, 2453 &srcY1, &srcU1, &srcV1, &srcY_pitch, &srcUV_pitch)) { 2454 return false; 2455 } 2456 srcY2 = srcY1 + srcY_pitch; 2457 srcU2 = srcU1 + srcUV_pitch; 2458 srcV2 = srcV1 + srcUV_pitch; 2459 src_pitch_left = (srcY_pitch - 4 * ((width + 1) / 2)); 2460 2461 if (!GetYUVPlanes(width, height, dst_format, dst, dst_pitch, 2462 (const Uint8 **)&dstY1, (const Uint8 **)&dstU, (const Uint8 **)&dstV, 2463 &dstY_pitch, &dstUV_pitch)) { 2464 return false; 2465 } 2466 dstY2 = dstY1 + dstY_pitch; 2467 dstY_pitch_left = (dstY_pitch - width); 2468 2469 if (dst_format == SDL_PIXELFORMAT_NV12 || dst_format == SDL_PIXELFORMAT_NV21) { 2470 dstUV_pixel_stride = 2; 2471 dstUV_pitch_left = (dstUV_pitch - 2 * ((width + 1) / 2)); 2472 } else { 2473 dstUV_pixel_stride = 1; 2474 dstUV_pitch_left = (dstUV_pitch - ((width + 1) / 2)); 2475 } 2476 2477 // Copy 2x2 blocks of pixels at a time 2478 for (y = 0; y < (height - 1); y += 2) { 2479 for (x = 0; x < (width - 1); x += 2) { 2480 // Row 1 2481 *dstY1++ = *srcY1; 2482 srcY1 += 2; 2483 *dstY1++ = *srcY1; 2484 srcY1 += 2; 2485 2486 // Row 2 2487 *dstY2++ = *srcY2; 2488 srcY2 += 2; 2489 *dstY2++ = *srcY2; 2490 srcY2 += 2; 2491 2492 *dstU = (Uint8)(((Uint32)*srcU1 + *srcU2) / 2); 2493 *dstV = (Uint8)(((Uint32)*srcV1 + *srcV2) / 2); 2494 2495 srcU1 += 4; 2496 srcU2 += 4; 2497 srcV1 += 4; 2498 srcV2 += 4; 2499 dstU += dstUV_pixel_stride; 2500 dstV += dstUV_pixel_stride; 2501 } 2502 2503 // Last column 2504 if (x == (width - 1)) { 2505 // Row 1 2506 *dstY1 = *srcY1; 2507 srcY1 += 2; 2508 *dstY1++ = *srcY1; 2509 srcY1 += 2; 2510 2511 // Row 2 2512 *dstY2 = *srcY2; 2513 srcY2 += 2; 2514 *dstY2++ = *srcY2; 2515 srcY2 += 2; 2516 2517 *dstU = (Uint8)(((Uint32)*srcU1 + *srcU2) / 2); 2518 *dstV = (Uint8)(((Uint32)*srcV1 + *srcV2) / 2); 2519 2520 srcU1 += 4; 2521 srcU2 += 4; 2522 srcV1 += 4; 2523 srcV2 += 4; 2524 dstU += dstUV_pixel_stride; 2525 dstV += dstUV_pixel_stride; 2526 } 2527 2528 srcY1 += src_pitch_left + srcY_pitch; 2529 srcY2 += src_pitch_left + srcY_pitch; 2530 srcU1 += src_pitch_left + srcUV_pitch; 2531 srcU2 += src_pitch_left + srcUV_pitch; 2532 srcV1 += src_pitch_left + srcUV_pitch; 2533 srcV2 += src_pitch_left + srcUV_pitch; 2534 dstY1 += dstY_pitch_left + dstY_pitch; 2535 dstY2 += dstY_pitch_left + dstY_pitch; 2536 dstU += dstUV_pitch_left; 2537 dstV += dstUV_pitch_left; 2538 } 2539 2540 // Last row 2541 if (y == (height - 1)) { 2542 for (x = 0; x < (width - 1); x += 2) { 2543 *dstY1++ = *srcY1; 2544 srcY1 += 2; 2545 *dstY1++ = *srcY1; 2546 srcY1 += 2; 2547 2548 *dstU = *srcU1; 2549 *dstV = *srcV1; 2550 2551 srcU1 += 4; 2552 srcV1 += 4; 2553 dstU += dstUV_pixel_stride; 2554 dstV += dstUV_pixel_stride; 2555 } 2556 2557 // Last column 2558 if (x == (width - 1)) { 2559 *dstY1 = *srcY1; 2560 *dstU = *srcU1; 2561 *dstV = *srcV1; 2562 } 2563 } 2564 return true; 2565} 2566 2567#endif // SDL_HAVE_YUV 2568 2569bool SDL_ConvertPixels_YUV_to_YUV(int width, int height, 2570 SDL_PixelFormat src_format, SDL_Colorspace src_colorspace, SDL_PropertiesID src_properties, const void *src, int src_pitch, 2571 SDL_PixelFormat dst_format, SDL_Colorspace dst_colorspace, SDL_PropertiesID dst_properties, void *dst, int dst_pitch) 2572{ 2573#ifdef SDL_HAVE_YUV 2574 if (src_colorspace != dst_colorspace) { 2575 return SDL_SetError("SDL_ConvertPixels_YUV_to_YUV: colorspace conversion not supported"); 2576 } 2577 2578 if (src_format == dst_format) { 2579 if (src == dst) { 2580 // Nothing to do 2581 return true; 2582 } 2583 return SDL_ConvertPixels_YUV_to_YUV_Copy(width, height, src_format, src, src_pitch, dst, dst_pitch); 2584 } 2585 2586 if (IsPlanar2x2Format(src_format) && IsPlanar2x2Format(dst_format)) { 2587 return SDL_ConvertPixels_Planar2x2_to_Planar2x2(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch); 2588 } else if (IsPacked4Format(src_format) && IsPacked4Format(dst_format)) { 2589 return SDL_ConvertPixels_Packed4_to_Packed4(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch); 2590 } else if (IsPlanar2x2Format(src_format) && IsPacked4Format(dst_format)) { 2591 return SDL_ConvertPixels_Planar2x2_to_Packed4(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch); 2592 } else if (IsPacked4Format(src_format) && IsPlanar2x2Format(dst_format)) { 2593 return SDL_ConvertPixels_Packed4_to_Planar2x2(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch); 2594 } else { 2595 return SDL_SetError("SDL_ConvertPixels_YUV_to_YUV: Unsupported YUV conversion: %s -> %s", SDL_GetPixelFormatName(src_format), 2596 SDL_GetPixelFormatName(dst_format)); 2597 } 2598#else 2599 return SDL_SetError("SDL not built with YUV support"); 2600#endif 2601} 2602[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.