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