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