Change std:vector to eina_array
[platform/upstream/SDL.git] / src / render / SDL_yuv_sw.c
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: */