00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 #include <inttypes.h>
00022 #include <string.h>
00023 #include <math.h>
00024 #include <stdio.h>
00025 #include "config.h"
00026 #include "swscale.h"
00027 #include "swscale_internal.h"
00028 #include "rgb2rgb.h"
00029 #include "libavutil/intreadwrite.h"
00030 #include "libavutil/cpu.h"
00031 #include "libavutil/avutil.h"
00032 #include "libavutil/mathematics.h"
00033 #include "libavutil/bswap.h"
00034 #include "libavutil/pixdesc.h"
00035 #include "libavutil/avassert.h"
00036 
00037 #define RGB2YUV_SHIFT 15
00038 #define BY ( (int) (0.114 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
00039 #define BV (-(int) (0.081 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
00040 #define BU ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
00041 #define GY ( (int) (0.587 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
00042 #define GV (-(int) (0.419 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
00043 #define GU (-(int) (0.331 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
00044 #define RY ( (int) (0.299 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
00045 #define RV ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
00046 #define RU (-(int) (0.169 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
00047 
00048 DECLARE_ALIGNED(8, const uint8_t, dithers)[8][8][8]={
00049 {
00050   {   0,  1,  0,  1,  0,  1,  0,  1,},
00051   {   1,  0,  1,  0,  1,  0,  1,  0,},
00052   {   0,  1,  0,  1,  0,  1,  0,  1,},
00053   {   1,  0,  1,  0,  1,  0,  1,  0,},
00054   {   0,  1,  0,  1,  0,  1,  0,  1,},
00055   {   1,  0,  1,  0,  1,  0,  1,  0,},
00056   {   0,  1,  0,  1,  0,  1,  0,  1,},
00057   {   1,  0,  1,  0,  1,  0,  1,  0,},
00058 },{
00059   {   1,  2,  1,  2,  1,  2,  1,  2,},
00060   {   3,  0,  3,  0,  3,  0,  3,  0,},
00061   {   1,  2,  1,  2,  1,  2,  1,  2,},
00062   {   3,  0,  3,  0,  3,  0,  3,  0,},
00063   {   1,  2,  1,  2,  1,  2,  1,  2,},
00064   {   3,  0,  3,  0,  3,  0,  3,  0,},
00065   {   1,  2,  1,  2,  1,  2,  1,  2,},
00066   {   3,  0,  3,  0,  3,  0,  3,  0,},
00067 },{
00068   {   2,  4,  3,  5,  2,  4,  3,  5,},
00069   {   6,  0,  7,  1,  6,  0,  7,  1,},
00070   {   3,  5,  2,  4,  3,  5,  2,  4,},
00071   {   7,  1,  6,  0,  7,  1,  6,  0,},
00072   {   2,  4,  3,  5,  2,  4,  3,  5,},
00073   {   6,  0,  7,  1,  6,  0,  7,  1,},
00074   {   3,  5,  2,  4,  3,  5,  2,  4,},
00075   {   7,  1,  6,  0,  7,  1,  6,  0,},
00076 },{
00077   {   4,  8,  7, 11,  4,  8,  7, 11,},
00078   {  12,  0, 15,  3, 12,  0, 15,  3,},
00079   {   6, 10,  5,  9,  6, 10,  5,  9,},
00080   {  14,  2, 13,  1, 14,  2, 13,  1,},
00081   {   4,  8,  7, 11,  4,  8,  7, 11,},
00082   {  12,  0, 15,  3, 12,  0, 15,  3,},
00083   {   6, 10,  5,  9,  6, 10,  5,  9,},
00084   {  14,  2, 13,  1, 14,  2, 13,  1,},
00085 },{
00086   {   9, 17, 15, 23,  8, 16, 14, 22,},
00087   {  25,  1, 31,  7, 24,  0, 30,  6,},
00088   {  13, 21, 11, 19, 12, 20, 10, 18,},
00089   {  29,  5, 27,  3, 28,  4, 26,  2,},
00090   {   8, 16, 14, 22,  9, 17, 15, 23,},
00091   {  24,  0, 30,  6, 25,  1, 31,  7,},
00092   {  12, 20, 10, 18, 13, 21, 11, 19,},
00093   {  28,  4, 26,  2, 29,  5, 27,  3,},
00094 },{
00095   {  18, 34, 30, 46, 17, 33, 29, 45,},
00096   {  50,  2, 62, 14, 49,  1, 61, 13,},
00097   {  26, 42, 22, 38, 25, 41, 21, 37,},
00098   {  58, 10, 54,  6, 57,  9, 53,  5,},
00099   {  16, 32, 28, 44, 19, 35, 31, 47,},
00100   {  48,  0, 60, 12, 51,  3, 63, 15,},
00101   {  24, 40, 20, 36, 27, 43, 23, 39,},
00102   {  56,  8, 52,  4, 59, 11, 55,  7,},
00103 },{
00104   {  18, 34, 30, 46, 17, 33, 29, 45,},
00105   {  50,  2, 62, 14, 49,  1, 61, 13,},
00106   {  26, 42, 22, 38, 25, 41, 21, 37,},
00107   {  58, 10, 54,  6, 57,  9, 53,  5,},
00108   {  16, 32, 28, 44, 19, 35, 31, 47,},
00109   {  48,  0, 60, 12, 51,  3, 63, 15,},
00110   {  24, 40, 20, 36, 27, 43, 23, 39,},
00111   {  56,  8, 52,  4, 59, 11, 55,  7,},
00112 },{
00113   {  36, 68, 60, 92, 34, 66, 58, 90,},
00114   { 100,  4,124, 28, 98,  2,122, 26,},
00115   {  52, 84, 44, 76, 50, 82, 42, 74,},
00116   { 116, 20,108, 12,114, 18,106, 10,},
00117   {  32, 64, 56, 88, 38, 70, 62, 94,},
00118   {  96,  0,120, 24,102,  6,126, 30,},
00119   {  48, 80, 40, 72, 54, 86, 46, 78,},
00120   { 112, 16,104,  8,118, 22,110, 14,},
00121 }};
00122 
00123 static const uint8_t flat64[8]={64,64,64,64,64,64,64,64};
00124 
00125 const uint16_t dither_scale[15][16]={
00126 {    2,    3,    3,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5,},
00127 {    2,    3,    7,    7,   13,   13,   25,   25,   25,   25,   25,   25,   25,   25,   25,   25,},
00128 {    3,    3,    4,   15,   15,   29,   57,   57,   57,  113,  113,  113,  113,  113,  113,  113,},
00129 {    3,    4,    4,    5,   31,   31,   61,  121,  241,  241,  241,  241,  481,  481,  481,  481,},
00130 {    3,    4,    5,    5,    6,   63,   63,  125,  249,  497,  993,  993,  993,  993,  993, 1985,},
00131 {    3,    5,    6,    6,    6,    7,  127,  127,  253,  505, 1009, 2017, 4033, 4033, 4033, 4033,},
00132 {    3,    5,    6,    7,    7,    7,    8,  255,  255,  509, 1017, 2033, 4065, 8129,16257,16257,},
00133 {    3,    5,    6,    8,    8,    8,    8,    9,  511,  511, 1021, 2041, 4081, 8161,16321,32641,},
00134 {    3,    5,    7,    8,    9,    9,    9,    9,   10, 1023, 1023, 2045, 4089, 8177,16353,32705,},
00135 {    3,    5,    7,    8,   10,   10,   10,   10,   10,   11, 2047, 2047, 4093, 8185,16369,32737,},
00136 {    3,    5,    7,    8,   10,   11,   11,   11,   11,   11,   12, 4095, 4095, 8189,16377,32753,},
00137 {    3,    5,    7,    9,   10,   12,   12,   12,   12,   12,   12,   13, 8191, 8191,16381,32761,},
00138 {    3,    5,    7,    9,   10,   12,   13,   13,   13,   13,   13,   13,   14,16383,16383,32765,},
00139 {    3,    5,    7,    9,   10,   12,   14,   14,   14,   14,   14,   14,   14,   15,32767,32767,},
00140 {    3,    5,    7,    9,   11,   12,   14,   15,   15,   15,   15,   15,   15,   15,   16,65535,},
00141 };
00142 
00143 
00144 static void fillPlane(uint8_t *plane, int stride, int width, int height, int y,
00145                       uint8_t val)
00146 {
00147     int i;
00148     uint8_t *ptr = plane + stride * y;
00149     for (i = 0; i < height; i++) {
00150         memset(ptr, val, width);
00151         ptr += stride;
00152     }
00153 }
00154 
00155 static void fillPlane16(uint8_t *plane, int stride, int width, int height, int y,
00156                       int alpha, int bits)
00157 {
00158     int i, j;
00159     uint8_t *ptr = plane + stride * y;
00160     int v = alpha ? -1 : (1<<bits);
00161     for (i = 0; i < height; i++) {
00162         for (j = 0; j < width; j++) {
00163             AV_WN16(ptr+2*j, v);
00164         }
00165         ptr += stride;
00166     }
00167 }
00168 
00169 static void copyPlane(const uint8_t *src, int srcStride,
00170                       int srcSliceY, int srcSliceH, int width,
00171                       uint8_t *dst, int dstStride)
00172 {
00173     dst += dstStride * srcSliceY;
00174     if (dstStride == srcStride && srcStride > 0) {
00175         memcpy(dst, src, srcSliceH * dstStride);
00176     } else {
00177         int i;
00178         for (i = 0; i < srcSliceH; i++) {
00179             memcpy(dst, src, width);
00180             src += srcStride;
00181             dst += dstStride;
00182         }
00183     }
00184 }
00185 
00186 static int planarToNv12Wrapper(SwsContext *c, const uint8_t *src[],
00187                                int srcStride[], int srcSliceY,
00188                                int srcSliceH, uint8_t *dstParam[],
00189                                int dstStride[])
00190 {
00191     uint8_t *dst = dstParam[1] + dstStride[1] * srcSliceY / 2;
00192 
00193     copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW,
00194               dstParam[0], dstStride[0]);
00195 
00196     if (c->dstFormat == PIX_FMT_NV12)
00197         interleaveBytes(src[1], src[2], dst, c->srcW / 2, srcSliceH / 2,
00198                         srcStride[1], srcStride[2], dstStride[0]);
00199     else
00200         interleaveBytes(src[2], src[1], dst, c->srcW / 2, srcSliceH / 2,
00201                         srcStride[2], srcStride[1], dstStride[0]);
00202 
00203     return srcSliceH;
00204 }
00205 
00206 static int planarToYuy2Wrapper(SwsContext *c, const uint8_t *src[],
00207                                int srcStride[], int srcSliceY, int srcSliceH,
00208                                uint8_t *dstParam[], int dstStride[])
00209 {
00210     uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
00211 
00212     yv12toyuy2(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
00213                srcStride[1], dstStride[0]);
00214 
00215     return srcSliceH;
00216 }
00217 
00218 static int planarToUyvyWrapper(SwsContext *c, const uint8_t *src[],
00219                                int srcStride[], int srcSliceY, int srcSliceH,
00220                                uint8_t *dstParam[], int dstStride[])
00221 {
00222     uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
00223 
00224     yv12touyvy(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
00225                srcStride[1], dstStride[0]);
00226 
00227     return srcSliceH;
00228 }
00229 
00230 static int yuv422pToYuy2Wrapper(SwsContext *c, const uint8_t *src[],
00231                                 int srcStride[], int srcSliceY, int srcSliceH,
00232                                 uint8_t *dstParam[], int dstStride[])
00233 {
00234     uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
00235 
00236     yuv422ptoyuy2(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
00237                   srcStride[1], dstStride[0]);
00238 
00239     return srcSliceH;
00240 }
00241 
00242 static int yuv422pToUyvyWrapper(SwsContext *c, const uint8_t *src[],
00243                                 int srcStride[], int srcSliceY, int srcSliceH,
00244                                 uint8_t *dstParam[], int dstStride[])
00245 {
00246     uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
00247 
00248     yuv422ptouyvy(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
00249                   srcStride[1], dstStride[0]);
00250 
00251     return srcSliceH;
00252 }
00253 
00254 static int yuyvToYuv420Wrapper(SwsContext *c, const uint8_t *src[],
00255                                int srcStride[], int srcSliceY, int srcSliceH,
00256                                uint8_t *dstParam[], int dstStride[])
00257 {
00258     uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
00259     uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY / 2;
00260     uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY / 2;
00261 
00262     yuyvtoyuv420(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
00263                  dstStride[1], srcStride[0]);
00264 
00265     if (dstParam[3])
00266         fillPlane(dstParam[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
00267 
00268     return srcSliceH;
00269 }
00270 
00271 static int yuyvToYuv422Wrapper(SwsContext *c, const uint8_t *src[],
00272                                int srcStride[], int srcSliceY, int srcSliceH,
00273                                uint8_t *dstParam[], int dstStride[])
00274 {
00275     uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
00276     uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY;
00277     uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY;
00278 
00279     yuyvtoyuv422(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
00280                  dstStride[1], srcStride[0]);
00281 
00282     return srcSliceH;
00283 }
00284 
00285 static int uyvyToYuv420Wrapper(SwsContext *c, const uint8_t *src[],
00286                                int srcStride[], int srcSliceY, int srcSliceH,
00287                                uint8_t *dstParam[], int dstStride[])
00288 {
00289     uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
00290     uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY / 2;
00291     uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY / 2;
00292 
00293     uyvytoyuv420(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
00294                  dstStride[1], srcStride[0]);
00295 
00296     if (dstParam[3])
00297         fillPlane(dstParam[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
00298 
00299     return srcSliceH;
00300 }
00301 
00302 static int uyvyToYuv422Wrapper(SwsContext *c, const uint8_t *src[],
00303                                int srcStride[], int srcSliceY, int srcSliceH,
00304                                uint8_t *dstParam[], int dstStride[])
00305 {
00306     uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
00307     uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY;
00308     uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY;
00309 
00310     uyvytoyuv422(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
00311                  dstStride[1], srcStride[0]);
00312 
00313     return srcSliceH;
00314 }
00315 
00316 static void gray8aToPacked32(const uint8_t *src, uint8_t *dst, int num_pixels,
00317                              const uint8_t *palette)
00318 {
00319     int i;
00320     for (i = 0; i < num_pixels; i++)
00321         ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i << 1]] | (src[(i << 1) + 1] << 24);
00322 }
00323 
00324 static void gray8aToPacked32_1(const uint8_t *src, uint8_t *dst, int num_pixels,
00325                                const uint8_t *palette)
00326 {
00327     int i;
00328 
00329     for (i = 0; i < num_pixels; i++)
00330         ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i << 1]] | src[(i << 1) + 1];
00331 }
00332 
00333 static void gray8aToPacked24(const uint8_t *src, uint8_t *dst, int num_pixels,
00334                              const uint8_t *palette)
00335 {
00336     int i;
00337 
00338     for (i = 0; i < num_pixels; i++) {
00339         
00340         dst[0] = palette[src[i << 1] * 4 + 0];
00341         dst[1] = palette[src[i << 1] * 4 + 1];
00342         dst[2] = palette[src[i << 1] * 4 + 2];
00343         dst += 3;
00344     }
00345 }
00346 
00347 static int packed_16bpc_bswap(SwsContext *c, const uint8_t *src[],
00348                               int srcStride[], int srcSliceY, int srcSliceH,
00349                               uint8_t *dst[], int dstStride[])
00350 {
00351     int i, j;
00352     int srcstr = srcStride[0] >> 1;
00353     int dststr = dstStride[0] >> 1;
00354     uint16_t       *dstPtr =       (uint16_t *) dst[0];
00355     const uint16_t *srcPtr = (const uint16_t *) src[0];
00356     int min_stride         = FFMIN(srcstr, dststr);
00357 
00358     for (i = 0; i < srcSliceH; i++) {
00359         for (j = 0; j < min_stride; j++) {
00360             dstPtr[j] = av_bswap16(srcPtr[j]);
00361         }
00362         srcPtr += srcstr;
00363         dstPtr += dststr;
00364     }
00365 
00366     return srcSliceH;
00367 }
00368 
00369 static int palToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[],
00370                            int srcSliceY, int srcSliceH, uint8_t *dst[],
00371                            int dstStride[])
00372 {
00373     const enum PixelFormat srcFormat = c->srcFormat;
00374     const enum PixelFormat dstFormat = c->dstFormat;
00375     void (*conv)(const uint8_t *src, uint8_t *dst, int num_pixels,
00376                  const uint8_t *palette) = NULL;
00377     int i;
00378     uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY;
00379     const uint8_t *srcPtr = src[0];
00380 
00381     if (srcFormat == PIX_FMT_GRAY8A) {
00382         switch (dstFormat) {
00383         case PIX_FMT_RGB32  : conv = gray8aToPacked32; break;
00384         case PIX_FMT_BGR32  : conv = gray8aToPacked32; break;
00385         case PIX_FMT_BGR32_1: conv = gray8aToPacked32_1; break;
00386         case PIX_FMT_RGB32_1: conv = gray8aToPacked32_1; break;
00387         case PIX_FMT_RGB24  : conv = gray8aToPacked24; break;
00388         case PIX_FMT_BGR24  : conv = gray8aToPacked24; break;
00389         }
00390     } else if (usePal(srcFormat)) {
00391         switch (dstFormat) {
00392         case PIX_FMT_RGB32  : conv = sws_convertPalette8ToPacked32; break;
00393         case PIX_FMT_BGR32  : conv = sws_convertPalette8ToPacked32; break;
00394         case PIX_FMT_BGR32_1: conv = sws_convertPalette8ToPacked32; break;
00395         case PIX_FMT_RGB32_1: conv = sws_convertPalette8ToPacked32; break;
00396         case PIX_FMT_RGB24  : conv = sws_convertPalette8ToPacked24; break;
00397         case PIX_FMT_BGR24  : conv = sws_convertPalette8ToPacked24; break;
00398         }
00399     }
00400 
00401     if (!conv)
00402         av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n",
00403                av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_name(dstFormat));
00404     else {
00405         for (i = 0; i < srcSliceH; i++) {
00406             conv(srcPtr, dstPtr, c->srcW, (uint8_t *) c->pal_rgb);
00407             srcPtr += srcStride[0];
00408             dstPtr += dstStride[0];
00409         }
00410     }
00411 
00412     return srcSliceH;
00413 }
00414 
00415 static void gbr24ptopacked24(const uint8_t *src[], int srcStride[],
00416                              uint8_t *dst, int dstStride, int srcSliceH,
00417                              int width)
00418 {
00419     int x, h, i;
00420     for (h = 0; h < srcSliceH; h++) {
00421         uint8_t *dest = dst + dstStride * h;
00422         for (x = 0; x < width; x++) {
00423             *dest++ = src[0][x];
00424             *dest++ = src[1][x];
00425             *dest++ = src[2][x];
00426         }
00427 
00428         for (i = 0; i < 3; i++)
00429             src[i] += srcStride[i];
00430     }
00431 }
00432 
00433 static void gbr24ptopacked32(const uint8_t *src[], int srcStride[],
00434                              uint8_t *dst, int dstStride, int srcSliceH,
00435                              int alpha_first, int width)
00436 {
00437     int x, h, i;
00438     for (h = 0; h < srcSliceH; h++) {
00439         uint8_t *dest = dst + dstStride * h;
00440 
00441         if (alpha_first) {
00442             for (x = 0; x < width; x++) {
00443                 *dest++ = 0xff;
00444                 *dest++ = src[0][x];
00445                 *dest++ = src[1][x];
00446                 *dest++ = src[2][x];
00447             }
00448         } else {
00449             for (x = 0; x < width; x++) {
00450                 *dest++ = src[0][x];
00451                 *dest++ = src[1][x];
00452                 *dest++ = src[2][x];
00453                 *dest++ = 0xff;
00454             }
00455         }
00456 
00457         for (i = 0; i < 3; i++)
00458             src[i] += srcStride[i];
00459     }
00460 }
00461 
00462 static int planarRgbToRgbWrapper(SwsContext *c, const uint8_t *src[],
00463                                  int srcStride[], int srcSliceY, int srcSliceH,
00464                                  uint8_t *dst[], int dstStride[])
00465 {
00466     int alpha_first = 0;
00467     if (c->srcFormat != PIX_FMT_GBRP) {
00468         av_log(c, AV_LOG_ERROR, "unsupported planar RGB conversion %s -> %s\n",
00469                av_get_pix_fmt_name(c->srcFormat),
00470                av_get_pix_fmt_name(c->dstFormat));
00471         return srcSliceH;
00472     }
00473 
00474     switch (c->dstFormat) {
00475     case PIX_FMT_BGR24:
00476         gbr24ptopacked24((const uint8_t *[]) { src[1], src[0], src[2] },
00477                          (int []) { srcStride[1], srcStride[0], srcStride[2] },
00478                          dst[0] + srcSliceY * dstStride[0], dstStride[0],
00479                          srcSliceH, c->srcW);
00480         break;
00481 
00482     case PIX_FMT_RGB24:
00483         gbr24ptopacked24((const uint8_t *[]) { src[2], src[0], src[1] },
00484                          (int []) { srcStride[2], srcStride[0], srcStride[1] },
00485                          dst[0] + srcSliceY * dstStride[0], dstStride[0],
00486                          srcSliceH, c->srcW);
00487         break;
00488 
00489     case PIX_FMT_ARGB:
00490         alpha_first = 1;
00491     case PIX_FMT_RGBA:
00492         gbr24ptopacked32((const uint8_t *[]) { src[2], src[0], src[1] },
00493                          (int []) { srcStride[2], srcStride[0], srcStride[1] },
00494                          dst[0] + srcSliceY * dstStride[0], dstStride[0],
00495                          srcSliceH, alpha_first, c->srcW);
00496         break;
00497 
00498     case PIX_FMT_ABGR:
00499         alpha_first = 1;
00500     case PIX_FMT_BGRA:
00501         gbr24ptopacked32((const uint8_t *[]) { src[1], src[0], src[2] },
00502                          (int []) { srcStride[1], srcStride[0], srcStride[2] },
00503                          dst[0] + srcSliceY * dstStride[0], dstStride[0],
00504                          srcSliceH, alpha_first, c->srcW);
00505         break;
00506 
00507     default:
00508         av_log(c, AV_LOG_ERROR,
00509                "unsupported planar RGB conversion %s -> %s\n",
00510                av_get_pix_fmt_name(c->srcFormat),
00511                av_get_pix_fmt_name(c->dstFormat));
00512     }
00513 
00514     return srcSliceH;
00515 }
00516 
00517 #define isRGBA32(x) (            \
00518            (x) == PIX_FMT_ARGB   \
00519         || (x) == PIX_FMT_RGBA   \
00520         || (x) == PIX_FMT_BGRA   \
00521         || (x) == PIX_FMT_ABGR   \
00522         )
00523 
00524 #define isRGBA64(x) (                \
00525            (x) == PIX_FMT_RGBA64LE   \
00526         || (x) == PIX_FMT_RGBA64BE   \
00527         || (x) == PIX_FMT_BGRA64LE   \
00528         || (x) == PIX_FMT_BGRA64BE   \
00529         )
00530 
00531 #define isRGB48(x) (                \
00532            (x) == PIX_FMT_RGB48LE   \
00533         || (x) == PIX_FMT_RGB48BE   \
00534         || (x) == PIX_FMT_BGR48LE   \
00535         || (x) == PIX_FMT_BGR48BE   \
00536         )
00537 
00538 
00539 typedef void (* rgbConvFn) (const uint8_t *, uint8_t *, int);
00540 static rgbConvFn findRgbConvFn(SwsContext *c)
00541 {
00542     const enum PixelFormat srcFormat = c->srcFormat;
00543     const enum PixelFormat dstFormat = c->dstFormat;
00544     const int srcId = c->srcFormatBpp;
00545     const int dstId = c->dstFormatBpp;
00546     rgbConvFn conv = NULL;
00547 
00548 #define IS_NOT_NE(bpp, fmt) \
00549     (((bpp + 7) >> 3) == 2 && \
00550      (!(av_pix_fmt_descriptors[fmt].flags & PIX_FMT_BE) != !HAVE_BIGENDIAN))
00551 
00552 #define CONV_IS(src, dst) (srcFormat == PIX_FMT_##src && dstFormat == PIX_FMT_##dst)
00553 
00554     if (isRGBA32(srcFormat) && isRGBA32(dstFormat)) {
00555         if (     CONV_IS(ABGR, RGBA)
00556               || CONV_IS(ARGB, BGRA)
00557               || CONV_IS(BGRA, ARGB)
00558               || CONV_IS(RGBA, ABGR)) conv = shuffle_bytes_3210;
00559         else if (CONV_IS(ABGR, ARGB)
00560               || CONV_IS(ARGB, ABGR)) conv = shuffle_bytes_0321;
00561         else if (CONV_IS(ABGR, BGRA)
00562               || CONV_IS(ARGB, RGBA)) conv = shuffle_bytes_1230;
00563         else if (CONV_IS(BGRA, RGBA)
00564               || CONV_IS(RGBA, BGRA)) conv = shuffle_bytes_2103;
00565         else if (CONV_IS(BGRA, ABGR)
00566               || CONV_IS(RGBA, ARGB)) conv = shuffle_bytes_3012;
00567     } else if (isRGB48(srcFormat) && isRGB48(dstFormat)) {
00568         if      (CONV_IS(RGB48LE, BGR48LE)
00569               || CONV_IS(BGR48LE, RGB48LE)
00570               || CONV_IS(RGB48BE, BGR48BE)
00571               || CONV_IS(BGR48BE, RGB48BE)) conv = rgb48tobgr48_nobswap;
00572         else if (CONV_IS(RGB48LE, BGR48BE)
00573               || CONV_IS(BGR48LE, RGB48BE)
00574               || CONV_IS(RGB48BE, BGR48LE)
00575               || CONV_IS(BGR48BE, RGB48LE)) conv = rgb48tobgr48_bswap;
00576     } else if (isRGBA64(srcFormat) && isRGB48(dstFormat)) {
00577         if      (CONV_IS(RGBA64LE, BGR48LE)
00578               || CONV_IS(BGRA64LE, RGB48LE)
00579               || CONV_IS(RGBA64BE, BGR48BE)
00580               || CONV_IS(BGRA64BE, RGB48BE)) conv = rgb64tobgr48_nobswap;
00581         else if (CONV_IS(RGBA64LE, BGR48BE)
00582               || CONV_IS(BGRA64LE, RGB48BE)
00583               || CONV_IS(RGBA64BE, BGR48LE)
00584               || CONV_IS(BGRA64BE, RGB48LE)) conv = rgb64tobgr48_bswap;
00585         else if (CONV_IS(RGBA64LE, RGB48LE)
00586               || CONV_IS(BGRA64LE, BGR48LE)
00587               || CONV_IS(RGBA64BE, RGB48BE)
00588               || CONV_IS(BGRA64BE, BGR48BE)) conv = rgb64to48_nobswap;
00589         else if (CONV_IS(RGBA64LE, RGB48BE)
00590               || CONV_IS(BGRA64LE, BGR48BE)
00591               || CONV_IS(RGBA64BE, RGB48LE)
00592               || CONV_IS(BGRA64BE, BGR48LE)) conv = rgb64to48_bswap;
00593     } else
00594     
00595     if ((isBGRinInt(srcFormat) && isBGRinInt(dstFormat)) ||
00596         (isRGBinInt(srcFormat) && isRGBinInt(dstFormat))) {
00597         switch (srcId | (dstId << 16)) {
00598         case 0x000F000C: conv = rgb12to15; break;
00599         case 0x000F0010: conv = rgb16to15; break;
00600         case 0x000F0018: conv = rgb24to15; break;
00601         case 0x000F0020: conv = rgb32to15; break;
00602         case 0x0010000F: conv = rgb15to16; break;
00603         case 0x00100018: conv = rgb24to16; break;
00604         case 0x00100020: conv = rgb32to16; break;
00605         case 0x0018000F: conv = rgb15to24; break;
00606         case 0x00180010: conv = rgb16to24; break;
00607         case 0x00180020: conv = rgb32to24; break;
00608         case 0x0020000F: conv = rgb15to32; break;
00609         case 0x00200010: conv = rgb16to32; break;
00610         case 0x00200018: conv = rgb24to32; break;
00611         }
00612     } else if ((isBGRinInt(srcFormat) && isRGBinInt(dstFormat)) ||
00613                (isRGBinInt(srcFormat) && isBGRinInt(dstFormat))) {
00614         switch (srcId | (dstId << 16)) {
00615         case 0x000C000C: conv = rgb12tobgr12; break;
00616         case 0x000F000F: conv = rgb15tobgr15; break;
00617         case 0x000F0010: conv = rgb16tobgr15; break;
00618         case 0x000F0018: conv = rgb24tobgr15; break;
00619         case 0x000F0020: conv = rgb32tobgr15; break;
00620         case 0x0010000F: conv = rgb15tobgr16; break;
00621         case 0x00100010: conv = rgb16tobgr16; break;
00622         case 0x00100018: conv = rgb24tobgr16; break;
00623         case 0x00100020: conv = rgb32tobgr16; break;
00624         case 0x0018000F: conv = rgb15tobgr24; break;
00625         case 0x00180010: conv = rgb16tobgr24; break;
00626         case 0x00180018: conv = rgb24tobgr24; break;
00627         case 0x00180020: conv = rgb32tobgr24; break;
00628         case 0x0020000F: conv = rgb15tobgr32; break;
00629         case 0x00200010: conv = rgb16tobgr32; break;
00630         case 0x00200018: conv = rgb24tobgr32; break;
00631         }
00632     }
00633 
00634     return conv;
00635 }
00636 
00637 
00638 static int rgbToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[],
00639                            int srcSliceY, int srcSliceH, uint8_t *dst[],
00640                            int dstStride[])
00641 
00642 {
00643     const enum PixelFormat srcFormat = c->srcFormat;
00644     const enum PixelFormat dstFormat = c->dstFormat;
00645     const int srcBpp = (c->srcFormatBpp + 7) >> 3;
00646     const int dstBpp = (c->dstFormatBpp + 7) >> 3;
00647     rgbConvFn conv = findRgbConvFn(c);
00648 
00649     if (!conv) {
00650         av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n",
00651                av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_name(dstFormat));
00652     } else {
00653         const uint8_t *srcPtr = src[0];
00654               uint8_t *dstPtr = dst[0];
00655         int src_bswap = IS_NOT_NE(c->srcFormatBpp, srcFormat);
00656         int dst_bswap = IS_NOT_NE(c->dstFormatBpp, dstFormat);
00657 
00658         if ((srcFormat == PIX_FMT_RGB32_1 || srcFormat == PIX_FMT_BGR32_1) &&
00659             !isRGBA32(dstFormat))
00660             srcPtr += ALT32_CORR;
00661 
00662         if ((dstFormat == PIX_FMT_RGB32_1 || dstFormat == PIX_FMT_BGR32_1) &&
00663             !isRGBA32(srcFormat))
00664             dstPtr += ALT32_CORR;
00665 
00666         if (dstStride[0] * srcBpp == srcStride[0] * dstBpp && srcStride[0] > 0 &&
00667             !(srcStride[0] % srcBpp) && !dst_bswap && !src_bswap)
00668             conv(srcPtr, dstPtr + dstStride[0] * srcSliceY,
00669                  srcSliceH * srcStride[0]);
00670         else {
00671             int i, j;
00672             dstPtr += dstStride[0] * srcSliceY;
00673 
00674             for (i = 0; i < srcSliceH; i++) {
00675                 if(src_bswap) {
00676                     for(j=0; j<c->srcW; j++)
00677                         ((uint16_t*)c->formatConvBuffer)[j] = av_bswap16(((uint16_t*)srcPtr)[j]);
00678                     conv(c->formatConvBuffer, dstPtr, c->srcW * srcBpp);
00679                 }else
00680                     conv(srcPtr, dstPtr, c->srcW * srcBpp);
00681                 if(dst_bswap)
00682                     for(j=0; j<c->srcW; j++)
00683                         ((uint16_t*)dstPtr)[j] = av_bswap16(((uint16_t*)dstPtr)[j]);
00684                 srcPtr += srcStride[0];
00685                 dstPtr += dstStride[0];
00686             }
00687         }
00688     }
00689     return srcSliceH;
00690 }
00691 
00692 static int bgr24ToYv12Wrapper(SwsContext *c, const uint8_t *src[],
00693                               int srcStride[], int srcSliceY, int srcSliceH,
00694                               uint8_t *dst[], int dstStride[])
00695 {
00696     rgb24toyv12(
00697         src[0],
00698         dst[0] +  srcSliceY       * dstStride[0],
00699         dst[1] + (srcSliceY >> 1) * dstStride[1],
00700         dst[2] + (srcSliceY >> 1) * dstStride[2],
00701         c->srcW, srcSliceH,
00702         dstStride[0], dstStride[1], srcStride[0]);
00703     if (dst[3])
00704         fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
00705     return srcSliceH;
00706 }
00707 
00708 static int yvu9ToYv12Wrapper(SwsContext *c, const uint8_t *src[],
00709                              int srcStride[], int srcSliceY, int srcSliceH,
00710                              uint8_t *dst[], int dstStride[])
00711 {
00712     copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW,
00713               dst[0], dstStride[0]);
00714 
00715     planar2x(src[1], dst[1] + dstStride[1] * (srcSliceY >> 1), c->chrSrcW,
00716              srcSliceH >> 2, srcStride[1], dstStride[1]);
00717     planar2x(src[2], dst[2] + dstStride[2] * (srcSliceY >> 1), c->chrSrcW,
00718              srcSliceH >> 2, srcStride[2], dstStride[2]);
00719     if (dst[3])
00720         fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
00721     return srcSliceH;
00722 }
00723 
00724 
00725 static int packedCopyWrapper(SwsContext *c, const uint8_t *src[],
00726                              int srcStride[], int srcSliceY, int srcSliceH,
00727                              uint8_t *dst[], int dstStride[])
00728 {
00729     if (dstStride[0] == srcStride[0] && srcStride[0] > 0)
00730         memcpy(dst[0] + dstStride[0] * srcSliceY, src[0], srcSliceH * dstStride[0]);
00731     else {
00732         int i;
00733         const uint8_t *srcPtr = src[0];
00734         uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY;
00735         int length = 0;
00736 
00737         
00738         while (length + c->srcW <= FFABS(dstStride[0]) &&
00739                length + c->srcW <= FFABS(srcStride[0]))
00740             length += c->srcW;
00741         av_assert1(length != 0);
00742 
00743         for (i = 0; i < srcSliceH; i++) {
00744             memcpy(dstPtr, srcPtr, length);
00745             srcPtr += srcStride[0];
00746             dstPtr += dstStride[0];
00747         }
00748     }
00749     return srcSliceH;
00750 }
00751 
00752 #define DITHER_COPY(dst, dstStride, src, srcStride, bswap, dbswap)\
00753     uint16_t scale= dither_scale[dst_depth-1][src_depth-1];\
00754     int shift= src_depth-dst_depth + dither_scale[src_depth-2][dst_depth-1];\
00755     for (i = 0; i < height; i++) {\
00756         const uint8_t *dither= dithers[src_depth-9][i&7];\
00757         for (j = 0; j < length-7; j+=8){\
00758             dst[j+0] = dbswap((bswap(src[j+0]) + dither[0])*scale>>shift);\
00759             dst[j+1] = dbswap((bswap(src[j+1]) + dither[1])*scale>>shift);\
00760             dst[j+2] = dbswap((bswap(src[j+2]) + dither[2])*scale>>shift);\
00761             dst[j+3] = dbswap((bswap(src[j+3]) + dither[3])*scale>>shift);\
00762             dst[j+4] = dbswap((bswap(src[j+4]) + dither[4])*scale>>shift);\
00763             dst[j+5] = dbswap((bswap(src[j+5]) + dither[5])*scale>>shift);\
00764             dst[j+6] = dbswap((bswap(src[j+6]) + dither[6])*scale>>shift);\
00765             dst[j+7] = dbswap((bswap(src[j+7]) + dither[7])*scale>>shift);\
00766         }\
00767         for (; j < length; j++)\
00768             dst[j] = dbswap((bswap(src[j]) + dither[j&7])*scale>>shift);\
00769         dst += dstStride;\
00770         src += srcStride;\
00771     }
00772 
00773 static int planarCopyWrapper(SwsContext *c, const uint8_t *src[],
00774                              int srcStride[], int srcSliceY, int srcSliceH,
00775                              uint8_t *dst[], int dstStride[])
00776 {
00777     int plane, i, j;
00778     for (plane = 0; plane < 4; plane++) {
00779         int length = (plane == 0 || plane == 3) ? c->srcW  : -((-c->srcW  ) >> c->chrDstHSubSample);
00780         int y =      (plane == 0 || plane == 3) ? srcSliceY: -((-srcSliceY) >> c->chrDstVSubSample);
00781         int height = (plane == 0 || plane == 3) ? srcSliceH: -((-srcSliceH) >> c->chrDstVSubSample);
00782         const uint8_t *srcPtr = src[plane];
00783         uint8_t *dstPtr = dst[plane] + dstStride[plane] * y;
00784         int shiftonly= plane==1 || plane==2 || (!c->srcRange && plane==0);
00785 
00786         if (!dst[plane])
00787             continue;
00788         
00789         if (plane == 1 && !dst[2]) continue;
00790         if (!src[plane] || (plane == 1 && !src[2])) {
00791             if (is16BPS(c->dstFormat) || isNBPS(c->dstFormat)) {
00792                 fillPlane16(dst[plane], dstStride[plane], length, height, y,
00793                         plane == 3, av_pix_fmt_descriptors[c->dstFormat].comp[plane].depth_minus1);
00794             } else {
00795                 fillPlane(dst[plane], dstStride[plane], length, height, y,
00796                         (plane == 3) ? 255 : 128);
00797             }
00798         } else {
00799             if(isNBPS(c->srcFormat) || isNBPS(c->dstFormat)
00800                || (is16BPS(c->srcFormat) != is16BPS(c->dstFormat))
00801             ) {
00802                 const int src_depth = av_pix_fmt_descriptors[c->srcFormat].comp[plane].depth_minus1 + 1;
00803                 const int dst_depth = av_pix_fmt_descriptors[c->dstFormat].comp[plane].depth_minus1 + 1;
00804                 const uint16_t *srcPtr2 = (const uint16_t *) srcPtr;
00805                 uint16_t *dstPtr2 = (uint16_t*)dstPtr;
00806 
00807                 if (dst_depth == 8) {
00808                     if(isBE(c->srcFormat) == HAVE_BIGENDIAN){
00809                         DITHER_COPY(dstPtr, dstStride[plane], srcPtr2, srcStride[plane]/2, , )
00810                     } else {
00811                         DITHER_COPY(dstPtr, dstStride[plane], srcPtr2, srcStride[plane]/2, av_bswap16, )
00812                     }
00813                 } else if (src_depth == 8) {
00814                     for (i = 0; i < height; i++) {
00815                         #define COPY816(w)\
00816                         if(shiftonly){\
00817                             for (j = 0; j < length; j++)\
00818                                 w(&dstPtr2[j], srcPtr[j]<<(dst_depth-8));\
00819                         }else{\
00820                             for (j = 0; j < length; j++)\
00821                                 w(&dstPtr2[j], (srcPtr[j]<<(dst_depth-8)) |\
00822                                                (srcPtr[j]>>(2*8-dst_depth)));\
00823                         }
00824                         if(isBE(c->dstFormat)){
00825                             COPY816(AV_WB16)
00826                         } else {
00827                             COPY816(AV_WL16)
00828                         }
00829                         dstPtr2 += dstStride[plane]/2;
00830                         srcPtr  += srcStride[plane];
00831                     }
00832                 } else if (src_depth <= dst_depth) {
00833                     int orig_length = length;
00834                     for (i = 0; i < height; i++) {
00835                         if(isBE(c->srcFormat) == HAVE_BIGENDIAN &&
00836                            isBE(c->dstFormat) == HAVE_BIGENDIAN &&
00837                            shiftonly) {
00838                              unsigned shift = dst_depth - src_depth;
00839                              length = orig_length;
00840 #if HAVE_FAST_64BIT
00841 #define FAST_COPY_UP(shift) \
00842     for (j = 0; j < length - 3; j += 4) { \
00843         uint64_t v = AV_RN64A(srcPtr2 + j); \
00844         AV_WN64A(dstPtr2 + j, v << shift); \
00845     } \
00846     length &= 3;
00847 #else
00848 #define FAST_COPY_UP(shift) \
00849     for (j = 0; j < length - 1; j += 2) { \
00850         uint32_t v = AV_RN32A(srcPtr2 + j); \
00851         AV_WN32A(dstPtr2 + j, v << shift); \
00852     } \
00853     length &= 1;
00854 #endif
00855                              switch (shift)
00856                              {
00857                              case 6: FAST_COPY_UP(6); break;
00858                              case 7: FAST_COPY_UP(7); break;
00859                              }
00860                         }
00861 #define COPY_UP(r,w) \
00862     if(shiftonly){\
00863         for (j = 0; j < length; j++){ \
00864             unsigned int v= r(&srcPtr2[j]);\
00865             w(&dstPtr2[j], v<<(dst_depth-src_depth));\
00866         }\
00867     }else{\
00868         for (j = 0; j < length; j++){ \
00869             unsigned int v= r(&srcPtr2[j]);\
00870             w(&dstPtr2[j], (v<<(dst_depth-src_depth)) | \
00871                         (v>>(2*src_depth-dst_depth)));\
00872         }\
00873     }
00874                         if(isBE(c->srcFormat)){
00875                             if(isBE(c->dstFormat)){
00876                                 COPY_UP(AV_RB16, AV_WB16)
00877                             } else {
00878                                 COPY_UP(AV_RB16, AV_WL16)
00879                             }
00880                         } else {
00881                             if(isBE(c->dstFormat)){
00882                                 COPY_UP(AV_RL16, AV_WB16)
00883                             } else {
00884                                 COPY_UP(AV_RL16, AV_WL16)
00885                             }
00886                         }
00887                         dstPtr2 += dstStride[plane]/2;
00888                         srcPtr2 += srcStride[plane]/2;
00889                     }
00890                 } else {
00891                     if(isBE(c->srcFormat) == HAVE_BIGENDIAN){
00892                         if(isBE(c->dstFormat) == HAVE_BIGENDIAN){
00893                             DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, , )
00894                         } else {
00895                             DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, , av_bswap16)
00896                         }
00897                     }else{
00898                         if(isBE(c->dstFormat) == HAVE_BIGENDIAN){
00899                             DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, av_bswap16, )
00900                         } else {
00901                             DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, av_bswap16, av_bswap16)
00902                         }
00903                     }
00904                 }
00905             } else if (is16BPS(c->srcFormat) && is16BPS(c->dstFormat) &&
00906                       isBE(c->srcFormat) != isBE(c->dstFormat)) {
00907 
00908                 for (i = 0; i < height; i++) {
00909                     for (j = 0; j < length; j++)
00910                         ((uint16_t *) dstPtr)[j] = av_bswap16(((const uint16_t *) srcPtr)[j]);
00911                     srcPtr += srcStride[plane];
00912                     dstPtr += dstStride[plane];
00913                 }
00914             } else if (dstStride[plane] == srcStride[plane] &&
00915                        srcStride[plane] > 0 && srcStride[plane] == length) {
00916                 memcpy(dst[plane] + dstStride[plane] * y, src[plane],
00917                        height * dstStride[plane]);
00918             } else {
00919                 if (is16BPS(c->srcFormat) && is16BPS(c->dstFormat))
00920                     length *= 2;
00921                 else if (!av_pix_fmt_descriptors[c->srcFormat].comp[0].depth_minus1)
00922                     length >>= 3; 
00923                 for (i = 0; i < height; i++) {
00924                     memcpy(dstPtr, srcPtr, length);
00925                     srcPtr += srcStride[plane];
00926                     dstPtr += dstStride[plane];
00927                 }
00928             }
00929         }
00930     }
00931     return srcSliceH;
00932 }
00933 
00934 
00935 #define IS_DIFFERENT_ENDIANESS(src_fmt, dst_fmt, pix_fmt)          \
00936     ((src_fmt == pix_fmt ## BE && dst_fmt == pix_fmt ## LE) ||     \
00937      (src_fmt == pix_fmt ## LE && dst_fmt == pix_fmt ## BE))
00938 
00939 
00940 void ff_get_unscaled_swscale(SwsContext *c)
00941 {
00942     const enum PixelFormat srcFormat = c->srcFormat;
00943     const enum PixelFormat dstFormat = c->dstFormat;
00944     const int flags = c->flags;
00945     const int dstH = c->dstH;
00946     int needsDither;
00947 
00948     needsDither = isAnyRGB(dstFormat) &&
00949             c->dstFormatBpp < 24 &&
00950            (c->dstFormatBpp < c->srcFormatBpp || (!isAnyRGB(srcFormat)));
00951 
00952     
00953     if ((srcFormat == PIX_FMT_YUV420P || srcFormat == PIX_FMT_YUVA420P) &&
00954         (dstFormat == PIX_FMT_NV12 || dstFormat == PIX_FMT_NV21)) {
00955         c->swScale = planarToNv12Wrapper;
00956     }
00957     
00958     if ((srcFormat == PIX_FMT_YUV420P || srcFormat == PIX_FMT_YUV422P ||
00959          srcFormat == PIX_FMT_YUVA420P) && isAnyRGB(dstFormat) &&
00960         !(flags & SWS_ACCURATE_RND) && !(dstH & 1)) {
00961         c->swScale = ff_yuv2rgb_get_func_ptr(c);
00962     }
00963 
00964     if (srcFormat == PIX_FMT_YUV410P &&
00965         (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P) &&
00966         !(flags & SWS_BITEXACT)) {
00967         c->swScale = yvu9ToYv12Wrapper;
00968     }
00969 
00970     
00971     if (srcFormat == PIX_FMT_BGR24 &&
00972         (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P) &&
00973         !(flags & SWS_ACCURATE_RND))
00974         c->swScale = bgr24ToYv12Wrapper;
00975 
00976     
00977     if (isAnyRGB(srcFormat) && isAnyRGB(dstFormat) && findRgbConvFn(c)
00978         && (!needsDither || (c->flags&(SWS_FAST_BILINEAR|SWS_POINT))))
00979         c->swScale= rgbToRgbWrapper;
00980 
00981 #define isByteRGB(f) (\
00982         f == PIX_FMT_RGB32   ||\
00983         f == PIX_FMT_RGB32_1 ||\
00984         f == PIX_FMT_RGB24   ||\
00985         f == PIX_FMT_BGR32   ||\
00986         f == PIX_FMT_BGR32_1 ||\
00987         f == PIX_FMT_BGR24)
00988 
00989     if (isAnyRGB(srcFormat) && isPlanar(srcFormat) && isByteRGB(dstFormat))
00990         c->swScale = planarRgbToRgbWrapper;
00991 
00992     
00993     if (IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_BGR444) ||
00994         IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_BGR48)  ||
00995         IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_BGRA64) ||
00996         IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_BGR555) ||
00997         IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_BGR565) ||
00998         IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_GRAY16) ||
00999         IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_RGB444) ||
01000         IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_RGB48)  ||
01001         IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_RGBA64) ||
01002         IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_RGB555) ||
01003         IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_RGB565))
01004         c->swScale = packed_16bpc_bswap;
01005 
01006     if (usePal(srcFormat) && isByteRGB(dstFormat))
01007         c->swScale = palToRgbWrapper;
01008 
01009     if (srcFormat == PIX_FMT_YUV422P) {
01010         if (dstFormat == PIX_FMT_YUYV422)
01011             c->swScale = yuv422pToYuy2Wrapper;
01012         else if (dstFormat == PIX_FMT_UYVY422)
01013             c->swScale = yuv422pToUyvyWrapper;
01014     }
01015 
01016     
01017     if (c->flags&(SWS_FAST_BILINEAR|SWS_POINT)) {
01018         
01019         if (srcFormat == PIX_FMT_YUV420P || srcFormat == PIX_FMT_YUVA420P) {
01020             if (dstFormat == PIX_FMT_YUYV422)
01021                 c->swScale = planarToYuy2Wrapper;
01022             else if (dstFormat == PIX_FMT_UYVY422)
01023                 c->swScale = planarToUyvyWrapper;
01024         }
01025     }
01026     if (srcFormat == PIX_FMT_YUYV422 &&
01027        (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P))
01028         c->swScale = yuyvToYuv420Wrapper;
01029     if (srcFormat == PIX_FMT_UYVY422 &&
01030        (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P))
01031         c->swScale = uyvyToYuv420Wrapper;
01032     if (srcFormat == PIX_FMT_YUYV422 && dstFormat == PIX_FMT_YUV422P)
01033         c->swScale = yuyvToYuv422Wrapper;
01034     if (srcFormat == PIX_FMT_UYVY422 && dstFormat == PIX_FMT_YUV422P)
01035         c->swScale = uyvyToYuv422Wrapper;
01036 
01037 #define isPlanarGray(x) (isGray(x) && (x) != PIX_FMT_GRAY8A)
01038     
01039     if ( srcFormat == dstFormat ||
01040         (srcFormat == PIX_FMT_YUVA420P && dstFormat == PIX_FMT_YUV420P) ||
01041         (srcFormat == PIX_FMT_YUV420P && dstFormat == PIX_FMT_YUVA420P) ||
01042         (isPlanarYUV(srcFormat) && isPlanarGray(dstFormat)) ||
01043         (isPlanarYUV(dstFormat) && isPlanarGray(srcFormat)) ||
01044         (isPlanarGray(dstFormat) && isPlanarGray(srcFormat)) ||
01045         (isPlanarYUV(srcFormat) && isPlanarYUV(dstFormat) &&
01046          c->chrDstHSubSample == c->chrSrcHSubSample &&
01047          c->chrDstVSubSample == c->chrSrcVSubSample &&
01048          dstFormat != PIX_FMT_NV12 && dstFormat != PIX_FMT_NV21 &&
01049          srcFormat != PIX_FMT_NV12 && srcFormat != PIX_FMT_NV21))
01050     {
01051         if (isPacked(c->srcFormat))
01052             c->swScale = packedCopyWrapper;
01053         else 
01054             c->swScale = planarCopyWrapper;
01055     }
01056 
01057     if (ARCH_BFIN)
01058         ff_bfin_get_unscaled_swscale(c);
01059     if (HAVE_ALTIVEC)
01060         ff_swscale_get_unscaled_altivec(c);
01061 }
01062 
01063 static void reset_ptr(const uint8_t *src[], int format)
01064 {
01065     if (!isALPHA(format))
01066         src[3] = NULL;
01067     if (!isPlanar(format)) {
01068         src[3] = src[2] = NULL;
01069 
01070         if (!usePal(format))
01071             src[1] = NULL;
01072     }
01073 }
01074 
01075 static int check_image_pointers(const uint8_t * const data[4], enum PixelFormat pix_fmt,
01076                                 const int linesizes[4])
01077 {
01078     const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[pix_fmt];
01079     int i;
01080 
01081     for (i = 0; i < 4; i++) {
01082         int plane = desc->comp[i].plane;
01083         if (!data[plane] || !linesizes[plane])
01084             return 0;
01085     }
01086 
01087     return 1;
01088 }
01089 
01094 int attribute_align_arg sws_scale(struct SwsContext *c,
01095                                   const uint8_t * const srcSlice[],
01096                                   const int srcStride[], int srcSliceY,
01097                                   int srcSliceH, uint8_t *const dst[],
01098                                   const int dstStride[])
01099 {
01100     int i, ret;
01101     const uint8_t *src2[4] = { srcSlice[0], srcSlice[1], srcSlice[2], srcSlice[3] };
01102     uint8_t *dst2[4] = { dst[0], dst[1], dst[2], dst[3] };
01103     uint8_t *rgb0_tmp = NULL;
01104 
01105     
01106     if (srcSliceH == 0)
01107         return 0;
01108 
01109     if (!check_image_pointers(srcSlice, c->srcFormat, srcStride)) {
01110         av_log(c, AV_LOG_ERROR, "bad src image pointers\n");
01111         return 0;
01112     }
01113     if (!check_image_pointers((const uint8_t* const*)dst, c->dstFormat, dstStride)) {
01114         av_log(c, AV_LOG_ERROR, "bad dst image pointers\n");
01115         return 0;
01116     }
01117 
01118     if (c->sliceDir == 0 && srcSliceY != 0 && srcSliceY + srcSliceH != c->srcH) {
01119         av_log(c, AV_LOG_ERROR, "Slices start in the middle!\n");
01120         return 0;
01121     }
01122     if (c->sliceDir == 0) {
01123         if (srcSliceY == 0) c->sliceDir = 1; else c->sliceDir = -1;
01124     }
01125 
01126     if (usePal(c->srcFormat)) {
01127         for (i = 0; i < 256; i++) {
01128             int p, r, g, b, y, u, v, a = 0xff;
01129             if (c->srcFormat == PIX_FMT_PAL8) {
01130                 p = ((const uint32_t *)(srcSlice[1]))[i];
01131                 a = (p >> 24) & 0xFF;
01132                 r = (p >> 16) & 0xFF;
01133                 g = (p >>  8) & 0xFF;
01134                 b =  p        & 0xFF;
01135             } else if (c->srcFormat == PIX_FMT_RGB8) {
01136                 r = ( i >> 5     ) * 36;
01137                 g = ((i >> 2) & 7) * 36;
01138                 b = ( i       & 3) * 85;
01139             } else if (c->srcFormat == PIX_FMT_BGR8) {
01140                 b = ( i >> 6     ) * 85;
01141                 g = ((i >> 3) & 7) * 36;
01142                 r = ( i       & 7) * 36;
01143             } else if (c->srcFormat == PIX_FMT_RGB4_BYTE) {
01144                 r = ( i >> 3     ) * 255;
01145                 g = ((i >> 1) & 3) * 85;
01146                 b = ( i       & 1) * 255;
01147             } else if (c->srcFormat == PIX_FMT_GRAY8 || c->srcFormat == PIX_FMT_GRAY8A) {
01148                 r = g = b = i;
01149             } else {
01150                 av_assert1(c->srcFormat == PIX_FMT_BGR4_BYTE);
01151                 b = ( i >> 3     ) * 255;
01152                 g = ((i >> 1) & 3) * 85;
01153                 r = ( i       & 1) * 255;
01154             }
01155             y = av_clip_uint8((RY * r + GY * g + BY * b + ( 33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
01156             u = av_clip_uint8((RU * r + GU * g + BU * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
01157             v = av_clip_uint8((RV * r + GV * g + BV * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
01158             c->pal_yuv[i]= y + (u<<8) + (v<<16) + (a<<24);
01159 
01160             switch (c->dstFormat) {
01161             case PIX_FMT_BGR32:
01162 #if !HAVE_BIGENDIAN
01163             case PIX_FMT_RGB24:
01164 #endif
01165                 c->pal_rgb[i]=  r + (g<<8) + (b<<16) + (a<<24);
01166                 break;
01167             case PIX_FMT_BGR32_1:
01168 #if HAVE_BIGENDIAN
01169             case PIX_FMT_BGR24:
01170 #endif
01171                 c->pal_rgb[i]= a + (r<<8) + (g<<16) + (b<<24);
01172                 break;
01173             case PIX_FMT_RGB32_1:
01174 #if HAVE_BIGENDIAN
01175             case PIX_FMT_RGB24:
01176 #endif
01177                 c->pal_rgb[i]= a + (b<<8) + (g<<16) + (r<<24);
01178                 break;
01179             case PIX_FMT_RGB32:
01180 #if !HAVE_BIGENDIAN
01181             case PIX_FMT_BGR24:
01182 #endif
01183             default:
01184                 c->pal_rgb[i]=  b + (g<<8) + (r<<16) + (a<<24);
01185             }
01186         }
01187     }
01188 
01189     if (c->src0Alpha && !c->dst0Alpha && isALPHA(c->dstFormat)) {
01190         uint8_t *base;
01191         int x,y;
01192         rgb0_tmp = av_malloc(FFABS(srcStride[0]) * srcSliceH + 32);
01193         base = srcStride[0] < 0 ? rgb0_tmp - srcStride[0] * (srcSliceH-1) : rgb0_tmp;
01194         for (y=0; y<srcSliceH; y++){
01195             memcpy(base + srcStride[0]*y, src2[0] + srcStride[0]*y, 4*c->srcW);
01196             for (x=c->src0Alpha-1; x<4*c->srcW; x+=4) {
01197                 base[ srcStride[0]*y + x] = 0xFF;
01198             }
01199         }
01200         src2[0] = base;
01201     }
01202 
01203     
01204     if (c->sliceDir == 1) {
01205         
01206         int srcStride2[4] = { srcStride[0], srcStride[1], srcStride[2],
01207                               srcStride[3] };
01208         int dstStride2[4] = { dstStride[0], dstStride[1], dstStride[2],
01209                               dstStride[3] };
01210 
01211         reset_ptr(src2, c->srcFormat);
01212         reset_ptr((void*)dst2, c->dstFormat);
01213 
01214         
01215         if (srcSliceY + srcSliceH == c->srcH)
01216             c->sliceDir = 0;
01217 
01218         ret = c->swScale(c, src2, srcStride2, srcSliceY, srcSliceH, dst2,
01219                           dstStride2);
01220     } else {
01221         
01222         int srcStride2[4] = { -srcStride[0], -srcStride[1], -srcStride[2],
01223                               -srcStride[3] };
01224         int dstStride2[4] = { -dstStride[0], -dstStride[1], -dstStride[2],
01225                               -dstStride[3] };
01226 
01227         src2[0] += (srcSliceH - 1) * srcStride[0];
01228         if (!usePal(c->srcFormat))
01229             src2[1] += ((srcSliceH >> c->chrSrcVSubSample) - 1) * srcStride[1];
01230         src2[2] += ((srcSliceH >> c->chrSrcVSubSample) - 1) * srcStride[2];
01231         src2[3] += (srcSliceH - 1) * srcStride[3];
01232         dst2[0] += ( c->dstH                         - 1) * dstStride[0];
01233         dst2[1] += ((c->dstH >> c->chrDstVSubSample) - 1) * dstStride[1];
01234         dst2[2] += ((c->dstH >> c->chrDstVSubSample) - 1) * dstStride[2];
01235         dst2[3] += ( c->dstH                         - 1) * dstStride[3];
01236 
01237         reset_ptr(src2, c->srcFormat);
01238         reset_ptr((void*)dst2, c->dstFormat);
01239 
01240         
01241         if (!srcSliceY)
01242             c->sliceDir = 0;
01243 
01244         ret = c->swScale(c, src2, srcStride2, c->srcH-srcSliceY-srcSliceH,
01245                           srcSliceH, dst2, dstStride2);
01246     }
01247 
01248     av_free(rgb0_tmp);
01249     return ret;
01250 }
01251 
01252 
01253 void sws_convertPalette8ToPacked32(const uint8_t *src, uint8_t *dst,
01254                                    int num_pixels, const uint8_t *palette)
01255 {
01256     int i;
01257 
01258     for (i = 0; i < num_pixels; i++)
01259         ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i]];
01260 }
01261 
01262 
01263 void sws_convertPalette8ToPacked24(const uint8_t *src, uint8_t *dst,
01264                                    int num_pixels, const uint8_t *palette)
01265 {
01266     int i;
01267 
01268     for (i = 0; i < num_pixels; i++) {
01269         
01270         dst[0] = palette[src[i] * 4 + 0];
01271         dst[1] = palette[src[i] * 4 + 1];
01272         dst[2] = palette[src[i] * 4 + 2];
01273         dst += 3;
01274     }
01275 }