1/*
2 * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
3 *
4 * This file is part of Libav.
5 *
6 * Libav is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * Libav is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Libav; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <inttypes.h>
22#include <string.h>
23#include <math.h>
24#include <stdio.h>
25#include "config.h"
26#include <assert.h>
27#include "swscale.h"
28#include "swscale_internal.h"
29#include "rgb2rgb.h"
30#include "libavutil/intreadwrite.h"
31#include "libavutil/cpu.h"
32#include "libavutil/avutil.h"
33#include "libavutil/mathematics.h"
34#include "libavutil/bswap.h"
35#include "libavutil/pixdesc.h"
36
37DECLARE_ALIGNED(8, const uint8_t, dither_8x8_1)[8][8] = {
38    {   0,  1,  0,  1,  0,  1,  0,  1,},
39    {   1,  0,  1,  0,  1,  0,  1,  0,},
40    {   0,  1,  0,  1,  0,  1,  0,  1,},
41    {   1,  0,  1,  0,  1,  0,  1,  0,},
42    {   0,  1,  0,  1,  0,  1,  0,  1,},
43    {   1,  0,  1,  0,  1,  0,  1,  0,},
44    {   0,  1,  0,  1,  0,  1,  0,  1,},
45    {   1,  0,  1,  0,  1,  0,  1,  0,},
46};
47DECLARE_ALIGNED(8, const uint8_t, dither_8x8_3)[8][8] = {
48    {   1,  2,  1,  2,  1,  2,  1,  2,},
49    {   3,  0,  3,  0,  3,  0,  3,  0,},
50    {   1,  2,  1,  2,  1,  2,  1,  2,},
51    {   3,  0,  3,  0,  3,  0,  3,  0,},
52    {   1,  2,  1,  2,  1,  2,  1,  2,},
53    {   3,  0,  3,  0,  3,  0,  3,  0,},
54    {   1,  2,  1,  2,  1,  2,  1,  2,},
55    {   3,  0,  3,  0,  3,  0,  3,  0,},
56};
57DECLARE_ALIGNED(8, const uint8_t, dither_8x8_64)[8][8] = {
58    {  18, 34, 30, 46, 17, 33, 29, 45,},
59    {  50,  2, 62, 14, 49,  1, 61, 13,},
60    {  26, 42, 22, 38, 25, 41, 21, 37,},
61    {  58, 10, 54,  6, 57,  9, 53,  5,},
62    {  16, 32, 28, 44, 19, 35, 31, 47,},
63    {  48,  0, 60, 12, 51,  3, 63, 15,},
64    {  24, 40, 20, 36, 27, 43, 23, 39,},
65    {  56,  8, 52,  4, 59, 11, 55,  7,},
66};
67extern const uint8_t dither_8x8_128[8][8];
68DECLARE_ALIGNED(8, const uint8_t, dither_8x8_256)[8][8] = {
69    {  72, 136, 120, 184,  68, 132, 116, 180,},
70    { 200,   8, 248,  56, 196,   4, 244,  52,},
71    { 104, 168,  88, 152, 100, 164,  84, 148,},
72    { 232,  40, 216,  24, 228,  36, 212,  20,},
73    {  64, 128, 102, 176,  76, 140, 124, 188,},
74    { 192,   0, 240,  48, 204,  12, 252,  60,},
75    {  96, 160,  80, 144, 108, 172,  92, 156,},
76    { 224,  32, 208,  16, 236,  44, 220,  28,},
77};
78
79#define RGB2YUV_SHIFT 15
80#define BY ( (int) (0.114 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
81#define BV (-(int) (0.081 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
82#define BU ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
83#define GY ( (int) (0.587 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
84#define GV (-(int) (0.419 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
85#define GU (-(int) (0.331 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
86#define RY ( (int) (0.299 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
87#define RV ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
88#define RU (-(int) (0.169 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
89
90static void fillPlane(uint8_t *plane, int stride, int width, int height, int y,
91                      uint8_t val)
92{
93    int i;
94    uint8_t *ptr = plane + stride * y;
95    for (i = 0; i < height; i++) {
96        memset(ptr, val, width);
97        ptr += stride;
98    }
99}
100
101static void copyPlane(const uint8_t *src, int srcStride,
102                      int srcSliceY, int srcSliceH, int width,
103                      uint8_t *dst, int dstStride)
104{
105    dst += dstStride * srcSliceY;
106    if (dstStride == srcStride && srcStride > 0) {
107        memcpy(dst, src, srcSliceH * dstStride);
108    } else {
109        int i;
110        for (i = 0; i < srcSliceH; i++) {
111            memcpy(dst, src, width);
112            src += srcStride;
113            dst += dstStride;
114        }
115    }
116}
117
118static int planarToNv12Wrapper(SwsContext *c, const uint8_t *src[],
119                               int srcStride[], int srcSliceY,
120                               int srcSliceH, uint8_t *dstParam[],
121                               int dstStride[])
122{
123    uint8_t *dst = dstParam[1] + dstStride[1] * srcSliceY / 2;
124
125    copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW,
126              dstParam[0], dstStride[0]);
127
128    if (c->dstFormat == PIX_FMT_NV12)
129        interleaveBytes(src[1], src[2], dst, c->srcW / 2, srcSliceH / 2,
130                        srcStride[1], srcStride[2], dstStride[0]);
131    else
132        interleaveBytes(src[2], src[1], dst, c->srcW / 2, srcSliceH / 2,
133                        srcStride[2], srcStride[1], dstStride[0]);
134
135    return srcSliceH;
136}
137
138static int planarToYuy2Wrapper(SwsContext *c, const uint8_t *src[],
139                               int srcStride[], int srcSliceY, int srcSliceH,
140                               uint8_t *dstParam[], int dstStride[])
141{
142    uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
143
144    yv12toyuy2(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
145               srcStride[1], dstStride[0]);
146
147    return srcSliceH;
148}
149
150static int planarToUyvyWrapper(SwsContext *c, const uint8_t *src[],
151                               int srcStride[], int srcSliceY, int srcSliceH,
152                               uint8_t *dstParam[], int dstStride[])
153{
154    uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
155
156    yv12touyvy(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
157               srcStride[1], dstStride[0]);
158
159    return srcSliceH;
160}
161
162static int yuv422pToYuy2Wrapper(SwsContext *c, const uint8_t *src[],
163                                int srcStride[], int srcSliceY, int srcSliceH,
164                                uint8_t *dstParam[], int dstStride[])
165{
166    uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
167
168    yuv422ptoyuy2(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
169                  srcStride[1], dstStride[0]);
170
171    return srcSliceH;
172}
173
174static int yuv422pToUyvyWrapper(SwsContext *c, const uint8_t *src[],
175                                int srcStride[], int srcSliceY, int srcSliceH,
176                                uint8_t *dstParam[], int dstStride[])
177{
178    uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
179
180    yuv422ptouyvy(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
181                  srcStride[1], dstStride[0]);
182
183    return srcSliceH;
184}
185
186static int yuyvToYuv420Wrapper(SwsContext *c, const uint8_t *src[],
187                               int srcStride[], int srcSliceY, int srcSliceH,
188                               uint8_t *dstParam[], int dstStride[])
189{
190    uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
191    uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY / 2;
192    uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY / 2;
193
194    yuyvtoyuv420(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
195                 dstStride[1], srcStride[0]);
196
197    if (dstParam[3])
198        fillPlane(dstParam[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
199
200    return srcSliceH;
201}
202
203static int yuyvToYuv422Wrapper(SwsContext *c, const uint8_t *src[],
204                               int srcStride[], int srcSliceY, int srcSliceH,
205                               uint8_t *dstParam[], int dstStride[])
206{
207    uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
208    uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY;
209    uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY;
210
211    yuyvtoyuv422(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
212                 dstStride[1], srcStride[0]);
213
214    return srcSliceH;
215}
216
217static int uyvyToYuv420Wrapper(SwsContext *c, const uint8_t *src[],
218                               int srcStride[], int srcSliceY, int srcSliceH,
219                               uint8_t *dstParam[], int dstStride[])
220{
221    uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
222    uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY / 2;
223    uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY / 2;
224
225    uyvytoyuv420(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
226                 dstStride[1], srcStride[0]);
227
228    if (dstParam[3])
229        fillPlane(dstParam[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
230
231    return srcSliceH;
232}
233
234static int uyvyToYuv422Wrapper(SwsContext *c, const uint8_t *src[],
235                               int srcStride[], int srcSliceY, int srcSliceH,
236                               uint8_t *dstParam[], int dstStride[])
237{
238    uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
239    uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY;
240    uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY;
241
242    uyvytoyuv422(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
243                 dstStride[1], srcStride[0]);
244
245    return srcSliceH;
246}
247
248static void gray8aToPacked32(const uint8_t *src, uint8_t *dst, int num_pixels,
249                             const uint8_t *palette)
250{
251    int i;
252    for (i = 0; i < num_pixels; i++)
253        ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i << 1]] | (src[(i << 1) + 1] << 24);
254}
255
256static void gray8aToPacked32_1(const uint8_t *src, uint8_t *dst, int num_pixels,
257                               const uint8_t *palette)
258{
259    int i;
260
261    for (i = 0; i < num_pixels; i++)
262        ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i << 1]] | src[(i << 1) + 1];
263}
264
265static void gray8aToPacked24(const uint8_t *src, uint8_t *dst, int num_pixels,
266                             const uint8_t *palette)
267{
268    int i;
269
270    for (i = 0; i < num_pixels; i++) {
271        //FIXME slow?
272        dst[0] = palette[src[i << 1] * 4 + 0];
273        dst[1] = palette[src[i << 1] * 4 + 1];
274        dst[2] = palette[src[i << 1] * 4 + 2];
275        dst += 3;
276    }
277}
278
279static int packed_16bpc_bswap(SwsContext *c, const uint8_t *src[],
280                              int srcStride[], int srcSliceY, int srcSliceH,
281                              uint8_t *dst[], int dstStride[])
282{
283    int i, j;
284    int srcstr = srcStride[0] >> 1;
285    int dststr = dstStride[0] >> 1;
286    uint16_t       *dstPtr =       (uint16_t *) dst[0];
287    const uint16_t *srcPtr = (const uint16_t *) src[0];
288    int min_stride         = FFMIN(srcstr, dststr);
289
290    for (i = 0; i < srcSliceH; i++) {
291        for (j = 0; j < min_stride; j++) {
292            dstPtr[j] = av_bswap16(srcPtr[j]);
293        }
294        srcPtr += srcstr;
295        dstPtr += dststr;
296    }
297
298    return srcSliceH;
299}
300
301static int palToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[],
302                           int srcSliceY, int srcSliceH, uint8_t *dst[],
303                           int dstStride[])
304{
305    const enum PixelFormat srcFormat = c->srcFormat;
306    const enum PixelFormat dstFormat = c->dstFormat;
307    void (*conv)(const uint8_t *src, uint8_t *dst, int num_pixels,
308                 const uint8_t *palette) = NULL;
309    int i;
310    uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY;
311    const uint8_t *srcPtr = src[0];
312
313    if (srcFormat == PIX_FMT_Y400A) {
314        switch (dstFormat) {
315        case PIX_FMT_RGB32  : conv = gray8aToPacked32; break;
316        case PIX_FMT_BGR32  : conv = gray8aToPacked32; break;
317        case PIX_FMT_BGR32_1: conv = gray8aToPacked32_1; break;
318        case PIX_FMT_RGB32_1: conv = gray8aToPacked32_1; break;
319        case PIX_FMT_RGB24  : conv = gray8aToPacked24; break;
320        case PIX_FMT_BGR24  : conv = gray8aToPacked24; break;
321        }
322    } else if (usePal(srcFormat)) {
323        switch (dstFormat) {
324        case PIX_FMT_RGB32  : conv = sws_convertPalette8ToPacked32; break;
325        case PIX_FMT_BGR32  : conv = sws_convertPalette8ToPacked32; break;
326        case PIX_FMT_BGR32_1: conv = sws_convertPalette8ToPacked32; break;
327        case PIX_FMT_RGB32_1: conv = sws_convertPalette8ToPacked32; break;
328        case PIX_FMT_RGB24  : conv = sws_convertPalette8ToPacked24; break;
329        case PIX_FMT_BGR24  : conv = sws_convertPalette8ToPacked24; break;
330        }
331    }
332
333    if (!conv)
334        av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n",
335               sws_format_name(srcFormat), sws_format_name(dstFormat));
336    else {
337        for (i = 0; i < srcSliceH; i++) {
338            conv(srcPtr, dstPtr, c->srcW, (uint8_t *) c->pal_rgb);
339            srcPtr += srcStride[0];
340            dstPtr += dstStride[0];
341        }
342    }
343
344    return srcSliceH;
345}
346
347#define isRGBA32(x) (            \
348           (x) == PIX_FMT_ARGB   \
349        || (x) == PIX_FMT_RGBA   \
350        || (x) == PIX_FMT_BGRA   \
351        || (x) == PIX_FMT_ABGR   \
352        )
353
354/* {RGB,BGR}{15,16,24,32,32_1} -> {RGB,BGR}{15,16,24,32} */
355typedef void (* rgbConvFn) (const uint8_t *, uint8_t *, int);
356static rgbConvFn findRgbConvFn(SwsContext *c)
357{
358    const enum PixelFormat srcFormat = c->srcFormat;
359    const enum PixelFormat dstFormat = c->dstFormat;
360    const int srcId = c->srcFormatBpp;
361    const int dstId = c->dstFormatBpp;
362    rgbConvFn conv = NULL;
363
364#define IS_NOT_NE(bpp, fmt) \
365    (((bpp + 7) >> 3) == 2 && \
366     (!(av_pix_fmt_descriptors[fmt].flags & PIX_FMT_BE) != !HAVE_BIGENDIAN))
367
368    /* if this is non-native rgb444/555/565, don't handle it here. */
369    if (IS_NOT_NE(srcId, srcFormat) || IS_NOT_NE(dstId, dstFormat))
370        return NULL;
371
372#define CONV_IS(src, dst) (srcFormat == PIX_FMT_##src && dstFormat == PIX_FMT_##dst)
373
374    if (isRGBA32(srcFormat) && isRGBA32(dstFormat)) {
375        if (     CONV_IS(ABGR, RGBA)
376              || CONV_IS(ARGB, BGRA)
377              || CONV_IS(BGRA, ARGB)
378              || CONV_IS(RGBA, ABGR)) conv = shuffle_bytes_3210;
379        else if (CONV_IS(ABGR, ARGB)
380              || CONV_IS(ARGB, ABGR)) conv = shuffle_bytes_0321;
381        else if (CONV_IS(ABGR, BGRA)
382              || CONV_IS(ARGB, RGBA)) conv = shuffle_bytes_1230;
383        else if (CONV_IS(BGRA, RGBA)
384              || CONV_IS(RGBA, BGRA)) conv = shuffle_bytes_2103;
385        else if (CONV_IS(BGRA, ABGR)
386              || CONV_IS(RGBA, ARGB)) conv = shuffle_bytes_3012;
387    } else
388    /* BGR -> BGR */
389    if ((isBGRinInt(srcFormat) && isBGRinInt(dstFormat)) ||
390        (isRGBinInt(srcFormat) && isRGBinInt(dstFormat))) {
391        switch (srcId | (dstId << 16)) {
392        case 0x000F000C: conv = rgb12to15; break;
393        case 0x000F0010: conv = rgb16to15; break;
394        case 0x000F0018: conv = rgb24to15; break;
395        case 0x000F0020: conv = rgb32to15; break;
396        case 0x0010000F: conv = rgb15to16; break;
397        case 0x00100018: conv = rgb24to16; break;
398        case 0x00100020: conv = rgb32to16; break;
399        case 0x0018000F: conv = rgb15to24; break;
400        case 0x00180010: conv = rgb16to24; break;
401        case 0x00180020: conv = rgb32to24; break;
402        case 0x0020000F: conv = rgb15to32; break;
403        case 0x00200010: conv = rgb16to32; break;
404        case 0x00200018: conv = rgb24to32; break;
405        }
406    } else if ((isBGRinInt(srcFormat) && isRGBinInt(dstFormat)) ||
407               (isRGBinInt(srcFormat) && isBGRinInt(dstFormat))) {
408        switch (srcId | (dstId << 16)) {
409        case 0x000C000C: conv = rgb12tobgr12; break;
410        case 0x000F000F: conv = rgb15tobgr15; break;
411        case 0x000F0010: conv = rgb16tobgr15; break;
412        case 0x000F0018: conv = rgb24tobgr15; break;
413        case 0x000F0020: conv = rgb32tobgr15; break;
414        case 0x0010000F: conv = rgb15tobgr16; break;
415        case 0x00100010: conv = rgb16tobgr16; break;
416        case 0x00100018: conv = rgb24tobgr16; break;
417        case 0x00100020: conv = rgb32tobgr16; break;
418        case 0x0018000F: conv = rgb15tobgr24; break;
419        case 0x00180010: conv = rgb16tobgr24; break;
420        case 0x00180018: conv = rgb24tobgr24; break;
421        case 0x00180020: conv = rgb32tobgr24; break;
422        case 0x0020000F: conv = rgb15tobgr32; break;
423        case 0x00200010: conv = rgb16tobgr32; break;
424        case 0x00200018: conv = rgb24tobgr32; break;
425        }
426    }
427
428    return conv;
429}
430
431/* {RGB,BGR}{15,16,24,32,32_1} -> {RGB,BGR}{15,16,24,32} */
432static int rgbToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[],
433                           int srcSliceY, int srcSliceH, uint8_t *dst[],
434                           int dstStride[])
435
436{
437    const enum PixelFormat srcFormat = c->srcFormat;
438    const enum PixelFormat dstFormat = c->dstFormat;
439    const int srcBpp = (c->srcFormatBpp + 7) >> 3;
440    const int dstBpp = (c->dstFormatBpp + 7) >> 3;
441    rgbConvFn conv = findRgbConvFn(c);
442
443    if (!conv) {
444        av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n",
445               sws_format_name(srcFormat), sws_format_name(dstFormat));
446    } else {
447        const uint8_t *srcPtr = src[0];
448              uint8_t *dstPtr = dst[0];
449        if ((srcFormat == PIX_FMT_RGB32_1 || srcFormat == PIX_FMT_BGR32_1) &&
450            !isRGBA32(dstFormat))
451            srcPtr += ALT32_CORR;
452
453        if ((dstFormat == PIX_FMT_RGB32_1 || dstFormat == PIX_FMT_BGR32_1) &&
454            !isRGBA32(srcFormat))
455            dstPtr += ALT32_CORR;
456
457        if (dstStride[0] * srcBpp == srcStride[0] * dstBpp && srcStride[0] > 0 &&
458            !(srcStride[0] % srcBpp))
459            conv(srcPtr, dstPtr + dstStride[0] * srcSliceY,
460                 srcSliceH * srcStride[0]);
461        else {
462            int i;
463            dstPtr += dstStride[0] * srcSliceY;
464
465            for (i = 0; i < srcSliceH; i++) {
466                conv(srcPtr, dstPtr, c->srcW * srcBpp);
467                srcPtr += srcStride[0];
468                dstPtr += dstStride[0];
469            }
470        }
471    }
472    return srcSliceH;
473}
474
475static int bgr24ToYv12Wrapper(SwsContext *c, const uint8_t *src[],
476                              int srcStride[], int srcSliceY, int srcSliceH,
477                              uint8_t *dst[], int dstStride[])
478{
479    rgb24toyv12(
480        src[0],
481        dst[0] +  srcSliceY       * dstStride[0],
482        dst[1] + (srcSliceY >> 1) * dstStride[1],
483        dst[2] + (srcSliceY >> 1) * dstStride[2],
484        c->srcW, srcSliceH,
485        dstStride[0], dstStride[1], srcStride[0]);
486    if (dst[3])
487        fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
488    return srcSliceH;
489}
490
491static int yvu9ToYv12Wrapper(SwsContext *c, const uint8_t *src[],
492                             int srcStride[], int srcSliceY, int srcSliceH,
493                             uint8_t *dst[], int dstStride[])
494{
495    copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW,
496              dst[0], dstStride[0]);
497
498    planar2x(src[1], dst[1] + dstStride[1] * (srcSliceY >> 1), c->chrSrcW,
499             srcSliceH >> 2, srcStride[1], dstStride[1]);
500    planar2x(src[2], dst[2] + dstStride[2] * (srcSliceY >> 1), c->chrSrcW,
501             srcSliceH >> 2, srcStride[2], dstStride[2]);
502    if (dst[3])
503        fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
504    return srcSliceH;
505}
506
507/* unscaled copy like stuff (assumes nearly identical formats) */
508static int packedCopyWrapper(SwsContext *c, const uint8_t *src[],
509                             int srcStride[], int srcSliceY, int srcSliceH,
510                             uint8_t *dst[], int dstStride[])
511{
512    if (dstStride[0] == srcStride[0] && srcStride[0] > 0)
513        memcpy(dst[0] + dstStride[0] * srcSliceY, src[0], srcSliceH * dstStride[0]);
514    else {
515        int i;
516        const uint8_t *srcPtr = src[0];
517        uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY;
518        int length = 0;
519
520        /* universal length finder */
521        while (length + c->srcW <= FFABS(dstStride[0]) &&
522               length + c->srcW <= FFABS(srcStride[0]))
523            length += c->srcW;
524        assert(length != 0);
525
526        for (i = 0; i < srcSliceH; i++) {
527            memcpy(dstPtr, srcPtr, length);
528            srcPtr += srcStride[0];
529            dstPtr += dstStride[0];
530        }
531    }
532    return srcSliceH;
533}
534
535#define clip9(x)  av_clip_uintp2(x,  9)
536#define clip10(x) av_clip_uintp2(x, 10)
537#define DITHER_COPY(dst, dstStride, wfunc, src, srcStride, rfunc, dithers, shift, clip) \
538    for (i = 0; i < height; i++) { \
539        const uint8_t *dither = dithers[i & 7]; \
540        for (j = 0; j < length - 7; j += 8) { \
541            wfunc(&dst[j + 0], clip((rfunc(&src[j + 0]) + dither[0]) >> shift)); \
542            wfunc(&dst[j + 1], clip((rfunc(&src[j + 1]) + dither[1]) >> shift)); \
543            wfunc(&dst[j + 2], clip((rfunc(&src[j + 2]) + dither[2]) >> shift)); \
544            wfunc(&dst[j + 3], clip((rfunc(&src[j + 3]) + dither[3]) >> shift)); \
545            wfunc(&dst[j + 4], clip((rfunc(&src[j + 4]) + dither[4]) >> shift)); \
546            wfunc(&dst[j + 5], clip((rfunc(&src[j + 5]) + dither[5]) >> shift)); \
547            wfunc(&dst[j + 6], clip((rfunc(&src[j + 6]) + dither[6]) >> shift)); \
548            wfunc(&dst[j + 7], clip((rfunc(&src[j + 7]) + dither[7]) >> shift)); \
549        } \
550        for (; j < length; j++) \
551            wfunc(&dst[j],     (rfunc(&src[j]) + dither[j & 7]) >> shift); \
552        dst += dstStride; \
553        src += srcStride; \
554    }
555
556static int planarCopyWrapper(SwsContext *c, const uint8_t *src[],
557                             int srcStride[], int srcSliceY, int srcSliceH,
558                             uint8_t *dst[], int dstStride[])
559{
560    int plane, i, j;
561    for (plane = 0; plane < 4; plane++) {
562        int length = (plane == 0 || plane == 3) ? c->srcW  : -((-c->srcW  ) >> c->chrDstHSubSample);
563        int y =      (plane == 0 || plane == 3) ? srcSliceY: -((-srcSliceY) >> c->chrDstVSubSample);
564        int height = (plane == 0 || plane == 3) ? srcSliceH: -((-srcSliceH) >> c->chrDstVSubSample);
565        const uint8_t *srcPtr = src[plane];
566        uint8_t *dstPtr = dst[plane] + dstStride[plane] * y;
567
568        if (!dst[plane])
569            continue;
570        // ignore palette for GRAY8
571        if (plane == 1 && !dst[2]) continue;
572        if (!src[plane] || (plane == 1 && !src[2])) {
573            if (is16BPS(c->dstFormat))
574                length *= 2;
575            fillPlane(dst[plane], dstStride[plane], length, height, y,
576                      (plane == 3) ? 255 : 128);
577        } else {
578            if (is9_OR_10BPS(c->srcFormat)) {
579                const int src_depth = av_pix_fmt_descriptors[c->srcFormat].comp[plane].depth_minus1 + 1;
580                const int dst_depth = av_pix_fmt_descriptors[c->dstFormat].comp[plane].depth_minus1 + 1;
581                const uint16_t *srcPtr2 = (const uint16_t *) srcPtr;
582
583                if (is16BPS(c->dstFormat)) {
584                    uint16_t *dstPtr2 = (uint16_t *) dstPtr;
585#define COPY9_OR_10TO16(rfunc, wfunc) \
586                    for (i = 0; i < height; i++) { \
587                        for (j = 0; j < length; j++) { \
588                            int srcpx = rfunc(&srcPtr2[j]); \
589                            wfunc(&dstPtr2[j], (srcpx << (16 - src_depth)) | (srcpx >> (2 * src_depth - 16))); \
590                        } \
591                        dstPtr2 += dstStride[plane] / 2; \
592                        srcPtr2 += srcStride[plane] / 2; \
593                    }
594                    if (isBE(c->dstFormat)) {
595                        if (isBE(c->srcFormat)) {
596                            COPY9_OR_10TO16(AV_RB16, AV_WB16);
597                        } else {
598                            COPY9_OR_10TO16(AV_RL16, AV_WB16);
599                        }
600                    } else {
601                        if (isBE(c->srcFormat)) {
602                            COPY9_OR_10TO16(AV_RB16, AV_WL16);
603                        } else {
604                            COPY9_OR_10TO16(AV_RL16, AV_WL16);
605                        }
606                    }
607                } else if (is9_OR_10BPS(c->dstFormat)) {
608                    uint16_t *dstPtr2 = (uint16_t *) dstPtr;
609#define COPY9_OR_10TO9_OR_10(loop) \
610                    for (i = 0; i < height; i++) { \
611                        for (j = 0; j < length; j++) { \
612                            loop; \
613                        } \
614                        dstPtr2 += dstStride[plane] / 2; \
615                        srcPtr2 += srcStride[plane] / 2; \
616                    }
617#define COPY9_OR_10TO9_OR_10_2(rfunc, wfunc) \
618                    if (dst_depth > src_depth) { \
619                        COPY9_OR_10TO9_OR_10(int srcpx = rfunc(&srcPtr2[j]); \
620                            wfunc(&dstPtr2[j], (srcpx << 1) | (srcpx >> 9))); \
621                    } else if (dst_depth < src_depth) { \
622                        DITHER_COPY(dstPtr2, dstStride[plane] / 2, wfunc, \
623                                    srcPtr2, srcStride[plane] / 2, rfunc, \
624                                    dither_8x8_1, 1, clip9); \
625                    } else { \
626                        COPY9_OR_10TO9_OR_10(wfunc(&dstPtr2[j], rfunc(&srcPtr2[j]))); \
627                    }
628                    if (isBE(c->dstFormat)) {
629                        if (isBE(c->srcFormat)) {
630                            COPY9_OR_10TO9_OR_10_2(AV_RB16, AV_WB16);
631                        } else {
632                            COPY9_OR_10TO9_OR_10_2(AV_RL16, AV_WB16);
633                        }
634                    } else {
635                        if (isBE(c->srcFormat)) {
636                            COPY9_OR_10TO9_OR_10_2(AV_RB16, AV_WL16);
637                        } else {
638                            COPY9_OR_10TO9_OR_10_2(AV_RL16, AV_WL16);
639                        }
640                    }
641                } else {
642#define W8(a, b) { *(a) = (b); }
643#define COPY9_OR_10TO8(rfunc) \
644                    if (src_depth == 9) { \
645                        DITHER_COPY(dstPtr,  dstStride[plane],   W8, \
646                                    srcPtr2, srcStride[plane] / 2, rfunc, \
647                                    dither_8x8_1, 1, av_clip_uint8); \
648                    } else { \
649                        DITHER_COPY(dstPtr,  dstStride[plane],   W8, \
650                                    srcPtr2, srcStride[plane] / 2, rfunc, \
651                                    dither_8x8_3, 2, av_clip_uint8); \
652                    }
653                    if (isBE(c->srcFormat)) {
654                        COPY9_OR_10TO8(AV_RB16);
655                    } else {
656                        COPY9_OR_10TO8(AV_RL16);
657                    }
658                }
659            } else if (is9_OR_10BPS(c->dstFormat)) {
660                const int dst_depth = av_pix_fmt_descriptors[c->dstFormat].comp[plane].depth_minus1 + 1;
661                uint16_t *dstPtr2 = (uint16_t *) dstPtr;
662
663                if (is16BPS(c->srcFormat)) {
664                    const uint16_t *srcPtr2 = (const uint16_t *) srcPtr;
665#define COPY16TO9_OR_10(rfunc, wfunc) \
666                    if (dst_depth == 9) { \
667                        DITHER_COPY(dstPtr2, dstStride[plane] / 2, wfunc, \
668                                    srcPtr2, srcStride[plane] / 2, rfunc, \
669                                    dither_8x8_128, 7, clip9); \
670                    } else { \
671                        DITHER_COPY(dstPtr2, dstStride[plane] / 2, wfunc, \
672                                    srcPtr2, srcStride[plane] / 2, rfunc, \
673                                    dither_8x8_64, 6, clip10); \
674                    }
675                    if (isBE(c->dstFormat)) {
676                        if (isBE(c->srcFormat)) {
677                            COPY16TO9_OR_10(AV_RB16, AV_WB16);
678                        } else {
679                            COPY16TO9_OR_10(AV_RL16, AV_WB16);
680                        }
681                    } else {
682                        if (isBE(c->srcFormat)) {
683                            COPY16TO9_OR_10(AV_RB16, AV_WL16);
684                        } else {
685                            COPY16TO9_OR_10(AV_RL16, AV_WL16);
686                        }
687                    }
688                } else /* 8bit */ {
689#define COPY8TO9_OR_10(wfunc) \
690                    for (i = 0; i < height; i++) { \
691                        for (j = 0; j < length; j++) { \
692                            const int srcpx = srcPtr[j]; \
693                            wfunc(&dstPtr2[j], (srcpx << (dst_depth - 8)) | (srcpx >> (16 - dst_depth))); \
694                        } \
695                        dstPtr2 += dstStride[plane] / 2; \
696                        srcPtr  += srcStride[plane]; \
697                    }
698                    if (isBE(c->dstFormat)) {
699                        COPY8TO9_OR_10(AV_WB16);
700                    } else {
701                        COPY8TO9_OR_10(AV_WL16);
702                    }
703                }
704            } else if (is16BPS(c->srcFormat) && !is16BPS(c->dstFormat)) {
705                const uint16_t *srcPtr2 = (const uint16_t *) srcPtr;
706#define COPY16TO8(rfunc) \
707                    DITHER_COPY(dstPtr,  dstStride[plane],   W8, \
708                                srcPtr2, srcStride[plane] / 2, rfunc, \
709                                dither_8x8_256, 8, av_clip_uint8);
710                if (isBE(c->srcFormat)) {
711                    COPY16TO8(AV_RB16);
712                } else {
713                    COPY16TO8(AV_RL16);
714                }
715            } else if (!is16BPS(c->srcFormat) && is16BPS(c->dstFormat)) {
716                for (i = 0; i < height; i++) {
717                    for (j = 0; j < length; j++) {
718                        dstPtr[ j << 1     ] = srcPtr[j];
719                        dstPtr[(j << 1) + 1] = srcPtr[j];
720                    }
721                    srcPtr += srcStride[plane];
722                    dstPtr += dstStride[plane];
723                }
724            } else if (is16BPS(c->srcFormat) && is16BPS(c->dstFormat) &&
725                      isBE(c->srcFormat) != isBE(c->dstFormat)) {
726
727                for (i = 0; i < height; i++) {
728                    for (j = 0; j < length; j++)
729                        ((uint16_t *) dstPtr)[j] = av_bswap16(((const uint16_t *) srcPtr)[j]);
730                    srcPtr += srcStride[plane];
731                    dstPtr += dstStride[plane];
732                }
733            } else if (dstStride[plane] == srcStride[plane] &&
734                       srcStride[plane] > 0 && srcStride[plane] == length) {
735                memcpy(dst[plane] + dstStride[plane] * y, src[plane],
736                       height * dstStride[plane]);
737            } else {
738                if (is16BPS(c->srcFormat) && is16BPS(c->dstFormat))
739                    length *= 2;
740                else if (!av_pix_fmt_descriptors[c->srcFormat].comp[0].depth_minus1)
741                    length >>= 3; // monowhite/black
742                for (i = 0; i < height; i++) {
743                    memcpy(dstPtr, srcPtr, length);
744                    srcPtr += srcStride[plane];
745                    dstPtr += dstStride[plane];
746                }
747            }
748        }
749    }
750    return srcSliceH;
751}
752
753
754#define IS_DIFFERENT_ENDIANESS(src_fmt, dst_fmt, pix_fmt)          \
755    ((src_fmt == pix_fmt ## BE && dst_fmt == pix_fmt ## LE) ||     \
756     (src_fmt == pix_fmt ## LE && dst_fmt == pix_fmt ## BE))
757
758
759void ff_get_unscaled_swscale(SwsContext *c)
760{
761    const enum PixelFormat srcFormat = c->srcFormat;
762    const enum PixelFormat dstFormat = c->dstFormat;
763    const int flags = c->flags;
764    const int dstH = c->dstH;
765    int needsDither;
766
767    needsDither = isAnyRGB(dstFormat) &&
768            c->dstFormatBpp < 24 &&
769           (c->dstFormatBpp < c->srcFormatBpp || (!isAnyRGB(srcFormat)));
770
771    /* yv12_to_nv12 */
772    if ((srcFormat == PIX_FMT_YUV420P || srcFormat == PIX_FMT_YUVA420P) &&
773        (dstFormat == PIX_FMT_NV12 || dstFormat == PIX_FMT_NV21)) {
774        c->swScale = planarToNv12Wrapper;
775    }
776    /* yuv2bgr */
777    if ((srcFormat == PIX_FMT_YUV420P || srcFormat == PIX_FMT_YUV422P ||
778         srcFormat == PIX_FMT_YUVA420P) && isAnyRGB(dstFormat) &&
779        !(flags & SWS_ACCURATE_RND) && !(dstH & 1)) {
780        c->swScale = ff_yuv2rgb_get_func_ptr(c);
781    }
782
783    if (srcFormat == PIX_FMT_YUV410P &&
784        (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P) &&
785        !(flags & SWS_BITEXACT)) {
786        c->swScale = yvu9ToYv12Wrapper;
787    }
788
789    /* bgr24toYV12 */
790    if (srcFormat == PIX_FMT_BGR24 &&
791        (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P) &&
792        !(flags & SWS_ACCURATE_RND))
793        c->swScale = bgr24ToYv12Wrapper;
794
795    /* RGB/BGR -> RGB/BGR (no dither needed forms) */
796    if (isAnyRGB(srcFormat) && isAnyRGB(dstFormat) && findRgbConvFn(c)
797        && (!needsDither || (c->flags&(SWS_FAST_BILINEAR|SWS_POINT))))
798        c->swScale= rgbToRgbWrapper;
799
800    /* bswap 16 bits per pixel/component packed formats */
801    if (IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_BGR444) ||
802        IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_BGR48)  ||
803        IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_BGR555) ||
804        IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_BGR565) ||
805        IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_GRAY16) ||
806        IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_RGB444) ||
807        IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_RGB48)  ||
808        IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_RGB555) ||
809        IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_RGB565))
810        c->swScale = packed_16bpc_bswap;
811
812    if ((usePal(srcFormat) && (
813        dstFormat == PIX_FMT_RGB32   ||
814        dstFormat == PIX_FMT_RGB32_1 ||
815        dstFormat == PIX_FMT_RGB24   ||
816        dstFormat == PIX_FMT_BGR32   ||
817        dstFormat == PIX_FMT_BGR32_1 ||
818        dstFormat == PIX_FMT_BGR24)))
819        c->swScale = palToRgbWrapper;
820
821    if (srcFormat == PIX_FMT_YUV422P) {
822        if (dstFormat == PIX_FMT_YUYV422)
823            c->swScale = yuv422pToYuy2Wrapper;
824        else if (dstFormat == PIX_FMT_UYVY422)
825            c->swScale = yuv422pToUyvyWrapper;
826    }
827
828    /* LQ converters if -sws 0 or -sws 4*/
829    if (c->flags&(SWS_FAST_BILINEAR|SWS_POINT)) {
830        /* yv12_to_yuy2 */
831        if (srcFormat == PIX_FMT_YUV420P || srcFormat == PIX_FMT_YUVA420P) {
832            if (dstFormat == PIX_FMT_YUYV422)
833                c->swScale = planarToYuy2Wrapper;
834            else if (dstFormat == PIX_FMT_UYVY422)
835                c->swScale = planarToUyvyWrapper;
836        }
837    }
838    if (srcFormat == PIX_FMT_YUYV422 &&
839       (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P))
840        c->swScale = yuyvToYuv420Wrapper;
841    if (srcFormat == PIX_FMT_UYVY422 &&
842       (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P))
843        c->swScale = uyvyToYuv420Wrapper;
844    if (srcFormat == PIX_FMT_YUYV422 && dstFormat == PIX_FMT_YUV422P)
845        c->swScale = yuyvToYuv422Wrapper;
846    if (srcFormat == PIX_FMT_UYVY422 && dstFormat == PIX_FMT_YUV422P)
847        c->swScale = uyvyToYuv422Wrapper;
848
849    /* simple copy */
850    if ( srcFormat == dstFormat ||
851        (srcFormat == PIX_FMT_YUVA420P && dstFormat == PIX_FMT_YUV420P) ||
852        (srcFormat == PIX_FMT_YUV420P && dstFormat == PIX_FMT_YUVA420P) ||
853        (isPlanarYUV(srcFormat) && isGray(dstFormat)) ||
854        (isPlanarYUV(dstFormat) && isGray(srcFormat)) ||
855        (isGray(dstFormat) && isGray(srcFormat)) ||
856        (isPlanarYUV(srcFormat) && isPlanarYUV(dstFormat) &&
857         c->chrDstHSubSample == c->chrSrcHSubSample &&
858         c->chrDstVSubSample == c->chrSrcVSubSample &&
859         dstFormat != PIX_FMT_NV12 && dstFormat != PIX_FMT_NV21 &&
860         srcFormat != PIX_FMT_NV12 && srcFormat != PIX_FMT_NV21))
861    {
862        if (isPacked(c->srcFormat))
863            c->swScale = packedCopyWrapper;
864        else /* Planar YUV or gray */
865            c->swScale = planarCopyWrapper;
866    }
867
868    if (ARCH_BFIN)
869        ff_bfin_get_unscaled_swscale(c);
870    if (HAVE_ALTIVEC)
871        ff_swscale_get_unscaled_altivec(c);
872}
873
874static void reset_ptr(const uint8_t *src[], int format)
875{
876    if (!isALPHA(format))
877        src[3] = NULL;
878    if (!isPlanar(format)) {
879        src[3] = src[2] = NULL;
880
881        if (!usePal(format))
882            src[1] = NULL;
883    }
884}
885
886static int check_image_pointers(uint8_t *data[4], enum PixelFormat pix_fmt,
887                                const int linesizes[4])
888{
889    const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[pix_fmt];
890    int i;
891
892    for (i = 0; i < 4; i++) {
893        int plane = desc->comp[i].plane;
894        if (!data[plane] || !linesizes[plane])
895            return 0;
896    }
897
898    return 1;
899}
900
901/**
902 * swscale wrapper, so we don't need to export the SwsContext.
903 * Assumes planar YUV to be in YUV order instead of YVU.
904 */
905int attribute_align_arg sws_scale(struct SwsContext *c,
906                                  const uint8_t * const srcSlice[],
907                                  const int srcStride[], int srcSliceY,
908                                  int srcSliceH, uint8_t *const dst[],
909                                  const int dstStride[])
910{
911    int i;
912    const uint8_t *src2[4] = { srcSlice[0], srcSlice[1], srcSlice[2], srcSlice[3] };
913    uint8_t *dst2[4] = { dst[0], dst[1], dst[2], dst[3] };
914
915    // do not mess up sliceDir if we have a "trailing" 0-size slice
916    if (srcSliceH == 0)
917        return 0;
918
919    if (!check_image_pointers(srcSlice, c->srcFormat, srcStride)) {
920        av_log(c, AV_LOG_ERROR, "bad src image pointers\n");
921        return 0;
922    }
923    if (!check_image_pointers(dst, c->dstFormat, dstStride)) {
924        av_log(c, AV_LOG_ERROR, "bad dst image pointers\n");
925        return 0;
926    }
927
928    if (c->sliceDir == 0 && srcSliceY != 0 && srcSliceY + srcSliceH != c->srcH) {
929        av_log(c, AV_LOG_ERROR, "Slices start in the middle!\n");
930        return 0;
931    }
932    if (c->sliceDir == 0) {
933        if (srcSliceY == 0) c->sliceDir = 1; else c->sliceDir = -1;
934    }
935
936    if (usePal(c->srcFormat)) {
937        for (i = 0; i < 256; i++) {
938            int p, r, g, b, y, u, v;
939            if (c->srcFormat == PIX_FMT_PAL8) {
940                p = ((const uint32_t *)(srcSlice[1]))[i];
941                r = (p >> 16) & 0xFF;
942                g = (p >>  8) & 0xFF;
943                b =  p        & 0xFF;
944            } else if (c->srcFormat == PIX_FMT_RGB8) {
945                r = ( i >> 5     ) * 36;
946                g = ((i >> 2) & 7) * 36;
947                b = ( i       & 3) * 85;
948            } else if (c->srcFormat == PIX_FMT_BGR8) {
949                b = ( i >> 6     ) * 85;
950                g = ((i >> 3) & 7) * 36;
951                r = ( i       & 7) * 36;
952            } else if (c->srcFormat == PIX_FMT_RGB4_BYTE) {
953                r = ( i >> 3     ) * 255;
954                g = ((i >> 1) & 3) * 85;
955                b = ( i       & 1) * 255;
956            } else if (c->srcFormat == PIX_FMT_GRAY8 ||
957                      c->srcFormat == PIX_FMT_Y400A) {
958                r = g = b = i;
959            } else {
960                assert(c->srcFormat == PIX_FMT_BGR4_BYTE);
961                b = ( i >> 3     ) * 255;
962                g = ((i >> 1) & 3) * 85;
963                r = ( i       & 1) * 255;
964            }
965            y = av_clip_uint8((RY * r + GY * g + BY * b + ( 33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
966            u = av_clip_uint8((RU * r + GU * g + BU * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
967            v = av_clip_uint8((RV * r + GV * g + BV * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
968            c->pal_yuv[i] = y + (u << 8) + (v << 16);
969
970            switch (c->dstFormat) {
971            case PIX_FMT_BGR32:
972#if !HAVE_BIGENDIAN
973            case PIX_FMT_RGB24:
974#endif
975                c->pal_rgb[i] =  r + (g << 8) + (b << 16);
976                break;
977            case PIX_FMT_BGR32_1:
978#if HAVE_BIGENDIAN
979            case PIX_FMT_BGR24:
980#endif
981                c->pal_rgb[i] = (r + (g << 8) + (b << 16)) << 8;
982                break;
983            case PIX_FMT_RGB32_1:
984#if HAVE_BIGENDIAN
985            case PIX_FMT_RGB24:
986#endif
987                c->pal_rgb[i] = (b + (g << 8) + (r << 16)) << 8;
988                break;
989            case PIX_FMT_RGB32:
990#if !HAVE_BIGENDIAN
991            case PIX_FMT_BGR24:
992#endif
993            default:
994                c->pal_rgb[i] =  b + (g << 8) + (r << 16);
995            }
996        }
997    }
998
999    // copy strides, so they can safely be modified
1000    if (c->sliceDir == 1) {
1001        // slices go from top to bottom
1002        int srcStride2[4] = { srcStride[0], srcStride[1], srcStride[2],
1003                              srcStride[3] };
1004        int dstStride2[4] = { dstStride[0], dstStride[1], dstStride[2],
1005                              dstStride[3] };
1006
1007        reset_ptr(src2, c->srcFormat);
1008        reset_ptr((const uint8_t **) dst2, c->dstFormat);
1009
1010        /* reset slice direction at end of frame */
1011        if (srcSliceY + srcSliceH == c->srcH)
1012            c->sliceDir = 0;
1013
1014        return c->swScale(c, src2, srcStride2, srcSliceY, srcSliceH, dst2,
1015                          dstStride2);
1016    } else {
1017        // slices go from bottom to top => we flip the image internally
1018        int srcStride2[4] = { -srcStride[0], -srcStride[1], -srcStride[2],
1019                              -srcStride[3] };
1020        int dstStride2[4] = { -dstStride[0], -dstStride[1], -dstStride[2],
1021                              -dstStride[3] };
1022
1023        src2[0] += (srcSliceH - 1) * srcStride[0];
1024        if (!usePal(c->srcFormat))
1025            src2[1] += ((srcSliceH >> c->chrSrcVSubSample) - 1) * srcStride[1];
1026        src2[2] += ((srcSliceH >> c->chrSrcVSubSample) - 1) * srcStride[2];
1027        src2[3] += (srcSliceH - 1) * srcStride[3];
1028        dst2[0] += ( c->dstH                         - 1) * dstStride[0];
1029        dst2[1] += ((c->dstH >> c->chrDstVSubSample) - 1) * dstStride[1];
1030        dst2[2] += ((c->dstH >> c->chrDstVSubSample) - 1) * dstStride[2];
1031        dst2[3] += ( c->dstH                         - 1) * dstStride[3];
1032
1033        reset_ptr(src2, c->srcFormat);
1034        reset_ptr((const uint8_t **) dst2, c->dstFormat);
1035
1036        /* reset slice direction at end of frame */
1037        if (!srcSliceY)
1038            c->sliceDir = 0;
1039
1040        return c->swScale(c, src2, srcStride2, c->srcH-srcSliceY-srcSliceH,
1041                          srcSliceH, dst2, dstStride2);
1042    }
1043}
1044
1045/* Convert the palette to the same packed 32-bit format as the palette */
1046void sws_convertPalette8ToPacked32(const uint8_t *src, uint8_t *dst,
1047                                   int num_pixels, const uint8_t *palette)
1048{
1049    int i;
1050
1051    for (i = 0; i < num_pixels; i++)
1052        ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i]];
1053}
1054
1055/* Palette format: ABCD -> dst format: ABC */
1056void sws_convertPalette8ToPacked24(const uint8_t *src, uint8_t *dst,
1057                                   int num_pixels, const uint8_t *palette)
1058{
1059    int i;
1060
1061    for (i = 0; i < num_pixels; i++) {
1062        //FIXME slow?
1063        dst[0] = palette[src[i] * 4 + 0];
1064        dst[1] = palette[src[i] * 4 + 1];
1065        dst[2] = palette[src[i] * 4 + 2];
1066        dst += 3;
1067    }
1068}
1069