2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "../SDL_internal.h"
23 /* This is the software implementation of the YUV texture support */
28 #include "SDL_yuv_sw_c.h"
32 SDL_SW_CreateYUVTexture(Uint32 format, int w, int h)
34 SDL_SW_YUVTexture *swdata;
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:
46 SDL_SetError("Unsupported YUV format");
50 swdata = (SDL_SW_YUVTexture *) SDL_calloc(1, sizeof(*swdata));
56 swdata->format = format;
57 swdata->target_format = SDL_PIXELFORMAT_UNKNOWN;
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;
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;
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;
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;
84 SDL_assert(0 && "We should never get here (caught above)");
87 swdata->pixels = (Uint8 *) SDL_malloc(dst_size);
88 if (!swdata->pixels) {
89 SDL_SW_DestroyYUVTexture(swdata);
95 /* Find the pitch and offset values for the texture */
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);
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;
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;
122 SDL_assert(0 && "We should never get here (caught above)");
126 /* We're all done.. */
131 SDL_SW_QueryYUVTexturePixels(SDL_SW_YUVTexture * swdata, void **pixels,
134 *pixels = swdata->planes[0];
135 *pitch = swdata->pitches[0];
140 SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
141 const void *pixels, int pitch)
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));
155 /* Copy the Y plane */
156 src = (Uint8 *) pixels;
157 dst = swdata->pixels + rect->y * swdata->w + rect->x;
159 for (row = 0; row < rect->h; ++row) {
160 SDL_memcpy(dst, src, length);
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;
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;
189 case SDL_PIXELFORMAT_YUY2:
190 case SDL_PIXELFORMAT_UYVY:
191 case SDL_PIXELFORMAT_YVYU:
197 src = (Uint8 *) pixels;
199 swdata->planes[0] + rect->y * swdata->pitches[0] +
201 length = 4 * ((rect->w + 1) / 2);
202 for (row = 0; row < rect->h; ++row) {
203 SDL_memcpy(dst, src, length);
205 dst += swdata->pitches[0];
209 case SDL_PIXELFORMAT_NV12:
210 case SDL_PIXELFORMAT_NV21:
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));
221 /* Copy the Y plane */
222 src = (Uint8 *) pixels;
223 dst = swdata->pixels + rect->y * swdata->w + rect->x;
225 for (row = 0; row < rect->h; ++row) {
226 SDL_memcpy(dst, src, length);
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);
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)
258 /* Copy the Y plane */
260 dst = swdata->pixels + rect->y * swdata->w + rect->x;
262 for (row = 0; row < rect->h; ++row) {
263 SDL_memcpy(dst, src, length);
268 /* Copy the U plane */
270 if (swdata->format == SDL_PIXELFORMAT_IYUV) {
271 dst = swdata->pixels + swdata->h * swdata->w;
273 dst = swdata->pixels + swdata->h * swdata->w +
274 ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2);
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);
281 dst += (swdata->w + 1)/2;
284 /* Copy the V plane */
286 if (swdata->format == SDL_PIXELFORMAT_YV12) {
287 dst = swdata->pixels + swdata->h * swdata->w;
289 dst = swdata->pixels + swdata->h * swdata->w +
290 ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2);
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);
297 dst += (swdata->w + 1)/2;
303 SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
304 void **pixels, int *pitch)
306 switch (swdata->format) {
307 case SDL_PIXELFORMAT_YV12:
308 case SDL_PIXELFORMAT_IYUV:
309 case SDL_PIXELFORMAT_NV12:
310 case SDL_PIXELFORMAT_NV21:
312 && (rect->x != 0 || rect->y != 0 || rect->w != swdata->w
313 || rect->h != swdata->h)) {
315 ("YV12, IYUV, NV12, NV21 textures only support full surface locks");
321 *pixels = swdata->planes[0] + rect->y * swdata->pitches[0] + rect->x * 2;
323 *pixels = swdata->planes[0];
325 *pitch = swdata->pitches[0];
330 SDL_SW_UnlockYUVTexture(SDL_SW_YUVTexture * swdata)
335 SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture * swdata, const SDL_Rect * srcrect,
336 Uint32 target_format, int w, int h, void *pixels,
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;
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.
355 } else if ((srcrect->w != w) || (srcrect->h != h)) {
360 Uint32 Rmask, Gmask, Bmask, Amask;
362 if (swdata->display) {
363 swdata->display->w = w;
364 swdata->display->h = h;
365 swdata->display->pixels = pixels;
366 swdata->display->pitch = pitch;
368 /* This must have succeeded in SDL_SW_SetupYUVDisplay() earlier */
369 SDL_PixelFormatEnumToMasks(target_format, &bpp, &Rmask, &Gmask,
372 SDL_CreateRGBSurfaceFrom(pixels, w, h, bpp, pitch, Rmask,
373 Gmask, Bmask, Amask);
374 if (!swdata->display) {
378 if (!swdata->stretch) {
379 /* This must have succeeded in SDL_SW_SetupYUVDisplay() earlier */
380 SDL_PixelFormatEnumToMasks(target_format, &bpp, &Rmask, &Gmask,
383 SDL_CreateRGBSurface(0, swdata->w, swdata->h, bpp, Rmask,
384 Gmask, Bmask, Amask);
385 if (!swdata->stretch) {
389 pixels = swdata->stretch->pixels;
390 pitch = swdata->stretch->pitch;
392 if (SDL_ConvertPixels(swdata->w, swdata->h, swdata->format,
393 swdata->planes[0], swdata->pitches[0],
394 target_format, pixels, pitch) < 0) {
398 SDL_Rect rect = *srcrect;
399 SDL_SoftStretch(swdata->stretch, &rect, swdata->display, NULL);
405 SDL_SW_DestroyYUVTexture(SDL_SW_YUVTexture * swdata)
408 SDL_free(swdata->pixels);
409 SDL_FreeSurface(swdata->stretch);
410 SDL_FreeSurface(swdata->display);
415 #endif /* SDL_HAVE_YUV */
417 /* vi: set ts=4 sw=4 expandtab: */