Libav 0.7.1
libswscale/swscale_unscaled.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
00003  *
00004  * This file is part of Libav.
00005  *
00006  * Libav is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * Libav is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with Libav; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 
00021 #include <inttypes.h>
00022 #include <string.h>
00023 #include <math.h>
00024 #include <stdio.h>
00025 #include "config.h"
00026 #include <assert.h>
00027 #include "swscale.h"
00028 #include "swscale_internal.h"
00029 #include "rgb2rgb.h"
00030 #include "libavutil/intreadwrite.h"
00031 #include "libavutil/cpu.h"
00032 #include "libavutil/avutil.h"
00033 #include "libavutil/mathematics.h"
00034 #include "libavutil/bswap.h"
00035 #include "libavutil/pixdesc.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 static void fillPlane(uint8_t* plane, int stride, int width, int height, int y, uint8_t val)
00049 {
00050     int i;
00051     uint8_t *ptr = plane + stride*y;
00052     for (i=0; i<height; i++) {
00053         memset(ptr, val, width);
00054         ptr += stride;
00055     }
00056 }
00057 
00058 static void copyPlane(const uint8_t *src, int srcStride,
00059                       int srcSliceY, int srcSliceH, int width,
00060                       uint8_t *dst, int dstStride)
00061 {
00062     dst += dstStride * srcSliceY;
00063     if (dstStride == srcStride && srcStride > 0) {
00064         memcpy(dst, src, srcSliceH * dstStride);
00065     } else {
00066         int i;
00067         for (i=0; i<srcSliceH; i++) {
00068             memcpy(dst, src, width);
00069             src += srcStride;
00070             dst += dstStride;
00071         }
00072     }
00073 }
00074 
00075 static int planarToNv12Wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00076                                int srcSliceH, uint8_t* dstParam[], int dstStride[])
00077 {
00078     uint8_t *dst = dstParam[1] + dstStride[1]*srcSliceY/2;
00079 
00080     copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW,
00081               dstParam[0], dstStride[0]);
00082 
00083     if (c->dstFormat == PIX_FMT_NV12)
00084         interleaveBytes(src[1], src[2], dst, c->srcW/2, srcSliceH/2, srcStride[1], srcStride[2], dstStride[0]);
00085     else
00086         interleaveBytes(src[2], src[1], dst, c->srcW/2, srcSliceH/2, srcStride[2], srcStride[1], dstStride[0]);
00087 
00088     return srcSliceH;
00089 }
00090 
00091 static int planarToYuy2Wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00092                                int srcSliceH, uint8_t* dstParam[], int dstStride[])
00093 {
00094     uint8_t *dst=dstParam[0] + dstStride[0]*srcSliceY;
00095 
00096     yv12toyuy2(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0], srcStride[1], dstStride[0]);
00097 
00098     return srcSliceH;
00099 }
00100 
00101 static int planarToUyvyWrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00102                                int srcSliceH, uint8_t* dstParam[], int dstStride[])
00103 {
00104     uint8_t *dst=dstParam[0] + dstStride[0]*srcSliceY;
00105 
00106     yv12touyvy(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0], srcStride[1], dstStride[0]);
00107 
00108     return srcSliceH;
00109 }
00110 
00111 static int yuv422pToYuy2Wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00112                                 int srcSliceH, uint8_t* dstParam[], int dstStride[])
00113 {
00114     uint8_t *dst=dstParam[0] + dstStride[0]*srcSliceY;
00115 
00116     yuv422ptoyuy2(src[0],src[1],src[2],dst,c->srcW,srcSliceH,srcStride[0],srcStride[1],dstStride[0]);
00117 
00118     return srcSliceH;
00119 }
00120 
00121 static int yuv422pToUyvyWrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00122                                 int srcSliceH, uint8_t* dstParam[], int dstStride[])
00123 {
00124     uint8_t *dst=dstParam[0] + dstStride[0]*srcSliceY;
00125 
00126     yuv422ptouyvy(src[0],src[1],src[2],dst,c->srcW,srcSliceH,srcStride[0],srcStride[1],dstStride[0]);
00127 
00128     return srcSliceH;
00129 }
00130 
00131 static int yuyvToYuv420Wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00132                                int srcSliceH, uint8_t* dstParam[], int dstStride[])
00133 {
00134     uint8_t *ydst=dstParam[0] + dstStride[0]*srcSliceY;
00135     uint8_t *udst=dstParam[1] + dstStride[1]*srcSliceY/2;
00136     uint8_t *vdst=dstParam[2] + dstStride[2]*srcSliceY/2;
00137 
00138     yuyvtoyuv420(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0], dstStride[1], srcStride[0]);
00139 
00140     if (dstParam[3])
00141         fillPlane(dstParam[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
00142 
00143     return srcSliceH;
00144 }
00145 
00146 static int yuyvToYuv422Wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00147                                int srcSliceH, uint8_t* dstParam[], int dstStride[])
00148 {
00149     uint8_t *ydst=dstParam[0] + dstStride[0]*srcSliceY;
00150     uint8_t *udst=dstParam[1] + dstStride[1]*srcSliceY;
00151     uint8_t *vdst=dstParam[2] + dstStride[2]*srcSliceY;
00152 
00153     yuyvtoyuv422(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0], dstStride[1], srcStride[0]);
00154 
00155     return srcSliceH;
00156 }
00157 
00158 static int uyvyToYuv420Wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00159                                int srcSliceH, uint8_t* dstParam[], int dstStride[])
00160 {
00161     uint8_t *ydst=dstParam[0] + dstStride[0]*srcSliceY;
00162     uint8_t *udst=dstParam[1] + dstStride[1]*srcSliceY/2;
00163     uint8_t *vdst=dstParam[2] + dstStride[2]*srcSliceY/2;
00164 
00165     uyvytoyuv420(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0], dstStride[1], srcStride[0]);
00166 
00167     if (dstParam[3])
00168         fillPlane(dstParam[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
00169 
00170     return srcSliceH;
00171 }
00172 
00173 static int uyvyToYuv422Wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00174                                int srcSliceH, uint8_t* dstParam[], int dstStride[])
00175 {
00176     uint8_t *ydst=dstParam[0] + dstStride[0]*srcSliceY;
00177     uint8_t *udst=dstParam[1] + dstStride[1]*srcSliceY;
00178     uint8_t *vdst=dstParam[2] + dstStride[2]*srcSliceY;
00179 
00180     uyvytoyuv422(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0], dstStride[1], srcStride[0]);
00181 
00182     return srcSliceH;
00183 }
00184 
00185 static void gray8aToPacked32(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette)
00186 {
00187     int i;
00188     for (i=0; i<num_pixels; i++)
00189         ((uint32_t *) dst)[i] = ((const uint32_t *)palette)[src[i<<1]] | (src[(i<<1)+1] << 24);
00190 }
00191 
00192 static void gray8aToPacked32_1(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette)
00193 {
00194     int i;
00195 
00196     for (i=0; i<num_pixels; i++)
00197         ((uint32_t *) dst)[i] = ((const uint32_t *)palette)[src[i<<1]] | src[(i<<1)+1];
00198 }
00199 
00200 static void gray8aToPacked24(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette)
00201 {
00202     int i;
00203 
00204     for (i=0; i<num_pixels; i++) {
00205         //FIXME slow?
00206         dst[0]= palette[src[i<<1]*4+0];
00207         dst[1]= palette[src[i<<1]*4+1];
00208         dst[2]= palette[src[i<<1]*4+2];
00209         dst+= 3;
00210     }
00211 }
00212 
00213 static int palToRgbWrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00214                            int srcSliceH, uint8_t* dst[], int dstStride[])
00215 {
00216     const enum PixelFormat srcFormat= c->srcFormat;
00217     const enum PixelFormat dstFormat= c->dstFormat;
00218     void (*conv)(const uint8_t *src, uint8_t *dst, int num_pixels,
00219                  const uint8_t *palette)=NULL;
00220     int i;
00221     uint8_t *dstPtr= dst[0] + dstStride[0]*srcSliceY;
00222     const uint8_t *srcPtr= src[0];
00223 
00224     if (srcFormat == PIX_FMT_Y400A) {
00225         switch (dstFormat) {
00226         case PIX_FMT_RGB32  : conv = gray8aToPacked32; break;
00227         case PIX_FMT_BGR32  : conv = gray8aToPacked32; break;
00228         case PIX_FMT_BGR32_1: conv = gray8aToPacked32_1; break;
00229         case PIX_FMT_RGB32_1: conv = gray8aToPacked32_1; break;
00230         case PIX_FMT_RGB24  : conv = gray8aToPacked24; break;
00231         case PIX_FMT_BGR24  : conv = gray8aToPacked24; break;
00232         }
00233     } else if (usePal(srcFormat)) {
00234         switch (dstFormat) {
00235         case PIX_FMT_RGB32  : conv = sws_convertPalette8ToPacked32; break;
00236         case PIX_FMT_BGR32  : conv = sws_convertPalette8ToPacked32; break;
00237         case PIX_FMT_BGR32_1: conv = sws_convertPalette8ToPacked32; break;
00238         case PIX_FMT_RGB32_1: conv = sws_convertPalette8ToPacked32; break;
00239         case PIX_FMT_RGB24  : conv = sws_convertPalette8ToPacked24; break;
00240         case PIX_FMT_BGR24  : conv = sws_convertPalette8ToPacked24; break;
00241         }
00242     }
00243 
00244     if (!conv)
00245         av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n",
00246                sws_format_name(srcFormat), sws_format_name(dstFormat));
00247     else {
00248         for (i=0; i<srcSliceH; i++) {
00249             conv(srcPtr, dstPtr, c->srcW, (uint8_t *) c->pal_rgb);
00250             srcPtr+= srcStride[0];
00251             dstPtr+= dstStride[0];
00252         }
00253     }
00254 
00255     return srcSliceH;
00256 }
00257 
00258 #define isRGBA32(x) (            \
00259            (x) == PIX_FMT_ARGB   \
00260         || (x) == PIX_FMT_RGBA   \
00261         || (x) == PIX_FMT_BGRA   \
00262         || (x) == PIX_FMT_ABGR   \
00263         )
00264 
00265 /* {RGB,BGR}{15,16,24,32,32_1} -> {RGB,BGR}{15,16,24,32} */
00266 static int rgbToRgbWrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00267                            int srcSliceH, uint8_t* dst[], int dstStride[])
00268 {
00269     const enum PixelFormat srcFormat= c->srcFormat;
00270     const enum PixelFormat dstFormat= c->dstFormat;
00271     const int srcBpp= (c->srcFormatBpp + 7) >> 3;
00272     const int dstBpp= (c->dstFormatBpp + 7) >> 3;
00273     const int srcId= c->srcFormatBpp >> 2; /* 1:0, 4:1, 8:2, 15:3, 16:4, 24:6, 32:8 */
00274     const int dstId= c->dstFormatBpp >> 2;
00275     void (*conv)(const uint8_t *src, uint8_t *dst, int src_size)=NULL;
00276 
00277 #define CONV_IS(src, dst) (srcFormat == PIX_FMT_##src && dstFormat == PIX_FMT_##dst)
00278 
00279     if (isRGBA32(srcFormat) && isRGBA32(dstFormat)) {
00280         if (     CONV_IS(ABGR, RGBA)
00281               || CONV_IS(ARGB, BGRA)
00282               || CONV_IS(BGRA, ARGB)
00283               || CONV_IS(RGBA, ABGR)) conv = shuffle_bytes_3210;
00284         else if (CONV_IS(ABGR, ARGB)
00285               || CONV_IS(ARGB, ABGR)) conv = shuffle_bytes_0321;
00286         else if (CONV_IS(ABGR, BGRA)
00287               || CONV_IS(ARGB, RGBA)) conv = shuffle_bytes_1230;
00288         else if (CONV_IS(BGRA, RGBA)
00289               || CONV_IS(RGBA, BGRA)) conv = shuffle_bytes_2103;
00290         else if (CONV_IS(BGRA, ABGR)
00291               || CONV_IS(RGBA, ARGB)) conv = shuffle_bytes_3012;
00292     } else
00293     /* BGR -> BGR */
00294     if (  (isBGRinInt(srcFormat) && isBGRinInt(dstFormat))
00295        || (isRGBinInt(srcFormat) && isRGBinInt(dstFormat))) {
00296         switch(srcId | (dstId<<4)) {
00297         case 0x34: conv= rgb16to15; break;
00298         case 0x36: conv= rgb24to15; break;
00299         case 0x38: conv= rgb32to15; break;
00300         case 0x43: conv= rgb15to16; break;
00301         case 0x46: conv= rgb24to16; break;
00302         case 0x48: conv= rgb32to16; break;
00303         case 0x63: conv= rgb15to24; break;
00304         case 0x64: conv= rgb16to24; break;
00305         case 0x68: conv= rgb32to24; break;
00306         case 0x83: conv= rgb15to32; break;
00307         case 0x84: conv= rgb16to32; break;
00308         case 0x86: conv= rgb24to32; break;
00309         }
00310     } else if (  (isBGRinInt(srcFormat) && isRGBinInt(dstFormat))
00311              || (isRGBinInt(srcFormat) && isBGRinInt(dstFormat))) {
00312         switch(srcId | (dstId<<4)) {
00313         case 0x33: conv= rgb15tobgr15; break;
00314         case 0x34: conv= rgb16tobgr15; break;
00315         case 0x36: conv= rgb24tobgr15; break;
00316         case 0x38: conv= rgb32tobgr15; break;
00317         case 0x43: conv= rgb15tobgr16; break;
00318         case 0x44: conv= rgb16tobgr16; break;
00319         case 0x46: conv= rgb24tobgr16; break;
00320         case 0x48: conv= rgb32tobgr16; break;
00321         case 0x63: conv= rgb15tobgr24; break;
00322         case 0x64: conv= rgb16tobgr24; break;
00323         case 0x66: conv= rgb24tobgr24; break;
00324         case 0x68: conv= rgb32tobgr24; break;
00325         case 0x83: conv= rgb15tobgr32; break;
00326         case 0x84: conv= rgb16tobgr32; break;
00327         case 0x86: conv= rgb24tobgr32; break;
00328         }
00329     }
00330 
00331     if (!conv) {
00332         av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n",
00333                sws_format_name(srcFormat), sws_format_name(dstFormat));
00334     } else {
00335         const uint8_t *srcPtr= src[0];
00336               uint8_t *dstPtr= dst[0];
00337         if ((srcFormat == PIX_FMT_RGB32_1 || srcFormat == PIX_FMT_BGR32_1) && !isRGBA32(dstFormat))
00338             srcPtr += ALT32_CORR;
00339 
00340         if ((dstFormat == PIX_FMT_RGB32_1 || dstFormat == PIX_FMT_BGR32_1) && !isRGBA32(srcFormat))
00341             dstPtr += ALT32_CORR;
00342 
00343         if (dstStride[0]*srcBpp == srcStride[0]*dstBpp && srcStride[0] > 0)
00344             conv(srcPtr, dstPtr + dstStride[0]*srcSliceY, srcSliceH*srcStride[0]);
00345         else {
00346             int i;
00347             dstPtr += dstStride[0]*srcSliceY;
00348 
00349             for (i=0; i<srcSliceH; i++) {
00350                 conv(srcPtr, dstPtr, c->srcW*srcBpp);
00351                 srcPtr+= srcStride[0];
00352                 dstPtr+= dstStride[0];
00353             }
00354         }
00355     }
00356     return srcSliceH;
00357 }
00358 
00359 static int bgr24ToYv12Wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00360                               int srcSliceH, uint8_t* dst[], int dstStride[])
00361 {
00362     rgb24toyv12(
00363         src[0],
00364         dst[0]+ srcSliceY    *dstStride[0],
00365         dst[1]+(srcSliceY>>1)*dstStride[1],
00366         dst[2]+(srcSliceY>>1)*dstStride[2],
00367         c->srcW, srcSliceH,
00368         dstStride[0], dstStride[1], srcStride[0]);
00369     if (dst[3])
00370         fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
00371     return srcSliceH;
00372 }
00373 
00374 static int yvu9ToYv12Wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00375                              int srcSliceH, uint8_t* dst[], int dstStride[])
00376 {
00377     copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW,
00378               dst[0], dstStride[0]);
00379 
00380     planar2x(src[1], dst[1] + dstStride[1]*(srcSliceY >> 1), c->chrSrcW,
00381              srcSliceH >> 2, srcStride[1], dstStride[1]);
00382     planar2x(src[2], dst[2] + dstStride[2]*(srcSliceY >> 1), c->chrSrcW,
00383              srcSliceH >> 2, srcStride[2], dstStride[2]);
00384     if (dst[3])
00385         fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
00386     return srcSliceH;
00387 }
00388 
00389 /* unscaled copy like stuff (assumes nearly identical formats) */
00390 static int packedCopyWrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00391                              int srcSliceH, uint8_t* dst[], int dstStride[])
00392 {
00393     if (dstStride[0]==srcStride[0] && srcStride[0] > 0)
00394         memcpy(dst[0] + dstStride[0]*srcSliceY, src[0], srcSliceH*dstStride[0]);
00395     else {
00396         int i;
00397         const uint8_t *srcPtr= src[0];
00398         uint8_t *dstPtr= dst[0] + dstStride[0]*srcSliceY;
00399         int length=0;
00400 
00401         /* universal length finder */
00402         while(length+c->srcW <= FFABS(dstStride[0])
00403            && length+c->srcW <= FFABS(srcStride[0])) length+= c->srcW;
00404         assert(length!=0);
00405 
00406         for (i=0; i<srcSliceH; i++) {
00407             memcpy(dstPtr, srcPtr, length);
00408             srcPtr+= srcStride[0];
00409             dstPtr+= dstStride[0];
00410         }
00411     }
00412     return srcSliceH;
00413 }
00414 
00415 static int planarCopyWrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00416                              int srcSliceH, uint8_t* dst[], int dstStride[])
00417 {
00418     int plane, i, j;
00419     for (plane=0; plane<4; plane++) {
00420         int length= (plane==0 || plane==3) ? c->srcW  : -((-c->srcW  )>>c->chrDstHSubSample);
00421         int y=      (plane==0 || plane==3) ? srcSliceY: -((-srcSliceY)>>c->chrDstVSubSample);
00422         int height= (plane==0 || plane==3) ? srcSliceH: -((-srcSliceH)>>c->chrDstVSubSample);
00423         const uint8_t *srcPtr= src[plane];
00424         uint8_t *dstPtr= dst[plane] + dstStride[plane]*y;
00425 
00426         if (!dst[plane]) continue;
00427         // ignore palette for GRAY8
00428         if (plane == 1 && !dst[2]) continue;
00429         if (!src[plane] || (plane == 1 && !src[2])) {
00430             if(is16BPS(c->dstFormat))
00431                 length*=2;
00432             fillPlane(dst[plane], dstStride[plane], length, height, y, (plane==3) ? 255 : 128);
00433         } else {
00434             if(is9_OR_10BPS(c->srcFormat)) {
00435                 const int src_depth = av_pix_fmt_descriptors[c->srcFormat].comp[plane].depth_minus1+1;
00436                 const int dst_depth = av_pix_fmt_descriptors[c->dstFormat].comp[plane].depth_minus1+1;
00437                 const uint16_t *srcPtr2 = (const uint16_t*)srcPtr;
00438 
00439                 if (is16BPS(c->dstFormat)) {
00440                     uint16_t *dstPtr2 = (uint16_t*)dstPtr;
00441 #define COPY9_OR_10TO16(rfunc, wfunc) \
00442                     for (i = 0; i < height; i++) { \
00443                         for (j = 0; j < length; j++) { \
00444                             int srcpx = rfunc(&srcPtr2[j]); \
00445                             wfunc(&dstPtr2[j], (srcpx<<(16-src_depth)) | (srcpx>>(2*src_depth-16))); \
00446                         } \
00447                         dstPtr2 += dstStride[plane]/2; \
00448                         srcPtr2 += srcStride[plane]/2; \
00449                     }
00450                     if (isBE(c->dstFormat)) {
00451                         if (isBE(c->srcFormat)) {
00452                             COPY9_OR_10TO16(AV_RB16, AV_WB16);
00453                         } else {
00454                             COPY9_OR_10TO16(AV_RL16, AV_WB16);
00455                         }
00456                     } else {
00457                         if (isBE(c->srcFormat)) {
00458                             COPY9_OR_10TO16(AV_RB16, AV_WL16);
00459                         } else {
00460                             COPY9_OR_10TO16(AV_RL16, AV_WL16);
00461                         }
00462                     }
00463                 } else if (is9_OR_10BPS(c->dstFormat)) {
00464                     uint16_t *dstPtr2 = (uint16_t*)dstPtr;
00465 #define COPY9_OR_10TO9_OR_10(loop) \
00466                     for (i = 0; i < height; i++) { \
00467                         for (j = 0; j < length; j++) { \
00468                             loop; \
00469                         } \
00470                         dstPtr2 += dstStride[plane]/2; \
00471                         srcPtr2 += srcStride[plane]/2; \
00472                     }
00473 #define COPY9_OR_10TO9_OR_10_2(rfunc, wfunc) \
00474                     if (dst_depth > src_depth) { \
00475                         COPY9_OR_10TO9_OR_10(int srcpx = rfunc(&srcPtr2[j]); \
00476                             wfunc(&dstPtr2[j], (srcpx << 1) | (srcpx >> 9))); \
00477                     } else if (dst_depth < src_depth) { \
00478                         COPY9_OR_10TO9_OR_10(wfunc(&dstPtr2[j], rfunc(&srcPtr2[j]) >> 1)); \
00479                     } else { \
00480                         COPY9_OR_10TO9_OR_10(wfunc(&dstPtr2[j], rfunc(&srcPtr2[j]))); \
00481                     }
00482                     if (isBE(c->dstFormat)) {
00483                         if (isBE(c->srcFormat)) {
00484                             COPY9_OR_10TO9_OR_10_2(AV_RB16, AV_WB16);
00485                         } else {
00486                             COPY9_OR_10TO9_OR_10_2(AV_RL16, AV_WB16);
00487                         }
00488                     } else {
00489                         if (isBE(c->srcFormat)) {
00490                             COPY9_OR_10TO9_OR_10_2(AV_RB16, AV_WL16);
00491                         } else {
00492                             COPY9_OR_10TO9_OR_10_2(AV_RL16, AV_WL16);
00493                         }
00494                     }
00495                 } else {
00496                     // FIXME Maybe dither instead.
00497 #define COPY9_OR_10TO8(rfunc) \
00498                     for (i = 0; i < height; i++) { \
00499                         for (j = 0; j < length; j++) { \
00500                             dstPtr[j] = rfunc(&srcPtr2[j])>>(src_depth-8); \
00501                         } \
00502                         dstPtr  += dstStride[plane]; \
00503                         srcPtr2 += srcStride[plane]/2; \
00504                     }
00505                     if (isBE(c->srcFormat)) {
00506                         COPY9_OR_10TO8(AV_RB16);
00507                     } else {
00508                         COPY9_OR_10TO8(AV_RL16);
00509                     }
00510                 }
00511             } else if(is9_OR_10BPS(c->dstFormat)) {
00512                 const int dst_depth = av_pix_fmt_descriptors[c->dstFormat].comp[plane].depth_minus1+1;
00513                 uint16_t *dstPtr2 = (uint16_t*)dstPtr;
00514 
00515                 if (is16BPS(c->srcFormat)) {
00516                     const uint16_t *srcPtr2 = (const uint16_t*)srcPtr;
00517 #define COPY16TO9_OR_10(rfunc, wfunc) \
00518                     for (i = 0; i < height; i++) { \
00519                         for (j = 0; j < length; j++) { \
00520                             wfunc(&dstPtr2[j], rfunc(&srcPtr2[j])>>(16-dst_depth)); \
00521                         } \
00522                         dstPtr2 += dstStride[plane]/2; \
00523                         srcPtr2 += srcStride[plane]/2; \
00524                     }
00525                     if (isBE(c->dstFormat)) {
00526                         if (isBE(c->srcFormat)) {
00527                             COPY16TO9_OR_10(AV_RB16, AV_WB16);
00528                         } else {
00529                             COPY16TO9_OR_10(AV_RL16, AV_WB16);
00530                         }
00531                     } else {
00532                         if (isBE(c->srcFormat)) {
00533                             COPY16TO9_OR_10(AV_RB16, AV_WL16);
00534                         } else {
00535                             COPY16TO9_OR_10(AV_RL16, AV_WL16);
00536                         }
00537                     }
00538                 } else /* 8bit */ {
00539 #define COPY8TO9_OR_10(wfunc) \
00540                     for (i = 0; i < height; i++) { \
00541                         for (j = 0; j < length; j++) { \
00542                             const int srcpx = srcPtr[j]; \
00543                             wfunc(&dstPtr2[j], (srcpx<<(dst_depth-8)) | (srcpx >> (16-dst_depth))); \
00544                         } \
00545                         dstPtr2 += dstStride[plane]/2; \
00546                         srcPtr  += srcStride[plane]; \
00547                     }
00548                     if (isBE(c->dstFormat)) {
00549                         COPY8TO9_OR_10(AV_WB16);
00550                     } else {
00551                         COPY8TO9_OR_10(AV_WL16);
00552                     }
00553                 }
00554             } else if(is16BPS(c->srcFormat) && !is16BPS(c->dstFormat)) {
00555                 if (!isBE(c->srcFormat)) srcPtr++;
00556                 for (i=0; i<height; i++) {
00557                     for (j=0; j<length; j++) dstPtr[j] = srcPtr[j<<1];
00558                     srcPtr+= srcStride[plane];
00559                     dstPtr+= dstStride[plane];
00560                 }
00561             } else if(!is16BPS(c->srcFormat) && is16BPS(c->dstFormat)) {
00562                 for (i=0; i<height; i++) {
00563                     for (j=0; j<length; j++) {
00564                         dstPtr[ j<<1   ] = srcPtr[j];
00565                         dstPtr[(j<<1)+1] = srcPtr[j];
00566                     }
00567                     srcPtr+= srcStride[plane];
00568                     dstPtr+= dstStride[plane];
00569                 }
00570             } else if(is16BPS(c->srcFormat) && is16BPS(c->dstFormat)
00571                   && isBE(c->srcFormat) != isBE(c->dstFormat)) {
00572 
00573                 for (i=0; i<height; i++) {
00574                     for (j=0; j<length; j++)
00575                         ((uint16_t*)dstPtr)[j] = av_bswap16(((const uint16_t*)srcPtr)[j]);
00576                     srcPtr+= srcStride[plane];
00577                     dstPtr+= dstStride[plane];
00578                 }
00579             } else if (dstStride[plane] == srcStride[plane] &&
00580                        srcStride[plane] > 0 && srcStride[plane] == length) {
00581                 memcpy(dst[plane] + dstStride[plane]*y, src[plane],
00582                        height*dstStride[plane]);
00583             } else {
00584                 if(is16BPS(c->srcFormat) && is16BPS(c->dstFormat))
00585                     length*=2;
00586                 for (i=0; i<height; i++) {
00587                     memcpy(dstPtr, srcPtr, length);
00588                     srcPtr+= srcStride[plane];
00589                     dstPtr+= dstStride[plane];
00590                 }
00591             }
00592         }
00593     }
00594     return srcSliceH;
00595 }
00596 
00597 void ff_get_unscaled_swscale(SwsContext *c)
00598 {
00599     const enum PixelFormat srcFormat = c->srcFormat;
00600     const enum PixelFormat dstFormat = c->dstFormat;
00601     const int flags = c->flags;
00602     const int dstH = c->dstH;
00603     int needsDither;
00604 
00605     needsDither= isAnyRGB(dstFormat)
00606         &&  c->dstFormatBpp < 24
00607         && (c->dstFormatBpp < c->srcFormatBpp || (!isAnyRGB(srcFormat)));
00608 
00609     /* yv12_to_nv12 */
00610     if ((srcFormat == PIX_FMT_YUV420P || srcFormat == PIX_FMT_YUVA420P) && (dstFormat == PIX_FMT_NV12 || dstFormat == PIX_FMT_NV21)) {
00611         c->swScale= planarToNv12Wrapper;
00612     }
00613     /* yuv2bgr */
00614     if ((srcFormat==PIX_FMT_YUV420P || srcFormat==PIX_FMT_YUV422P || srcFormat==PIX_FMT_YUVA420P) && isAnyRGB(dstFormat)
00615         && !(flags & SWS_ACCURATE_RND) && !(dstH&1)) {
00616         c->swScale= ff_yuv2rgb_get_func_ptr(c);
00617     }
00618 
00619     if (srcFormat==PIX_FMT_YUV410P && (dstFormat==PIX_FMT_YUV420P || dstFormat==PIX_FMT_YUVA420P) && !(flags & SWS_BITEXACT)) {
00620         c->swScale= yvu9ToYv12Wrapper;
00621     }
00622 
00623     /* bgr24toYV12 */
00624     if (srcFormat==PIX_FMT_BGR24 && (dstFormat==PIX_FMT_YUV420P || dstFormat==PIX_FMT_YUVA420P) && !(flags & SWS_ACCURATE_RND))
00625         c->swScale= bgr24ToYv12Wrapper;
00626 
00627     /* RGB/BGR -> RGB/BGR (no dither needed forms) */
00628     if (   isAnyRGB(srcFormat)
00629         && isAnyRGB(dstFormat)
00630         && srcFormat != PIX_FMT_BGR8      && dstFormat != PIX_FMT_BGR8
00631         && srcFormat != PIX_FMT_RGB8      && dstFormat != PIX_FMT_RGB8
00632         && srcFormat != PIX_FMT_BGR4      && dstFormat != PIX_FMT_BGR4
00633         && srcFormat != PIX_FMT_RGB4      && dstFormat != PIX_FMT_RGB4
00634         && srcFormat != PIX_FMT_BGR4_BYTE && dstFormat != PIX_FMT_BGR4_BYTE
00635         && srcFormat != PIX_FMT_RGB4_BYTE && dstFormat != PIX_FMT_RGB4_BYTE
00636         && srcFormat != PIX_FMT_MONOBLACK && dstFormat != PIX_FMT_MONOBLACK
00637         && srcFormat != PIX_FMT_MONOWHITE && dstFormat != PIX_FMT_MONOWHITE
00638         && srcFormat != PIX_FMT_RGB48LE   && dstFormat != PIX_FMT_RGB48LE
00639         && srcFormat != PIX_FMT_RGB48BE   && dstFormat != PIX_FMT_RGB48BE
00640         && srcFormat != PIX_FMT_BGR48LE   && dstFormat != PIX_FMT_BGR48LE
00641         && srcFormat != PIX_FMT_BGR48BE   && dstFormat != PIX_FMT_BGR48BE
00642         && (!needsDither || (c->flags&(SWS_FAST_BILINEAR|SWS_POINT))))
00643         c->swScale= rgbToRgbWrapper;
00644 
00645     if ((usePal(srcFormat) && (
00646         dstFormat == PIX_FMT_RGB32   ||
00647         dstFormat == PIX_FMT_RGB32_1 ||
00648         dstFormat == PIX_FMT_RGB24   ||
00649         dstFormat == PIX_FMT_BGR32   ||
00650         dstFormat == PIX_FMT_BGR32_1 ||
00651         dstFormat == PIX_FMT_BGR24)))
00652         c->swScale= palToRgbWrapper;
00653 
00654     if (srcFormat == PIX_FMT_YUV422P) {
00655         if (dstFormat == PIX_FMT_YUYV422)
00656             c->swScale= yuv422pToYuy2Wrapper;
00657         else if (dstFormat == PIX_FMT_UYVY422)
00658             c->swScale= yuv422pToUyvyWrapper;
00659     }
00660 
00661     /* LQ converters if -sws 0 or -sws 4*/
00662     if (c->flags&(SWS_FAST_BILINEAR|SWS_POINT)) {
00663         /* yv12_to_yuy2 */
00664         if (srcFormat == PIX_FMT_YUV420P || srcFormat == PIX_FMT_YUVA420P) {
00665             if (dstFormat == PIX_FMT_YUYV422)
00666                 c->swScale= planarToYuy2Wrapper;
00667             else if (dstFormat == PIX_FMT_UYVY422)
00668                 c->swScale= planarToUyvyWrapper;
00669         }
00670     }
00671     if(srcFormat == PIX_FMT_YUYV422 && (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P))
00672         c->swScale= yuyvToYuv420Wrapper;
00673     if(srcFormat == PIX_FMT_UYVY422 && (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P))
00674         c->swScale= uyvyToYuv420Wrapper;
00675     if(srcFormat == PIX_FMT_YUYV422 && dstFormat == PIX_FMT_YUV422P)
00676         c->swScale= yuyvToYuv422Wrapper;
00677     if(srcFormat == PIX_FMT_UYVY422 && dstFormat == PIX_FMT_YUV422P)
00678         c->swScale= uyvyToYuv422Wrapper;
00679 
00680     /* simple copy */
00681     if (  srcFormat == dstFormat
00682         || (srcFormat == PIX_FMT_YUVA420P && dstFormat == PIX_FMT_YUV420P)
00683         || (srcFormat == PIX_FMT_YUV420P && dstFormat == PIX_FMT_YUVA420P)
00684         || (isPlanarYUV(srcFormat) && isGray(dstFormat))
00685         || (isPlanarYUV(dstFormat) && isGray(srcFormat))
00686         || (isGray(dstFormat) && isGray(srcFormat))
00687         || (isPlanarYUV(srcFormat) && isPlanarYUV(dstFormat)
00688             && c->chrDstHSubSample == c->chrSrcHSubSample
00689             && c->chrDstVSubSample == c->chrSrcVSubSample
00690             && dstFormat != PIX_FMT_NV12 && dstFormat != PIX_FMT_NV21
00691             && srcFormat != PIX_FMT_NV12 && srcFormat != PIX_FMT_NV21))
00692     {
00693         if (isPacked(c->srcFormat))
00694             c->swScale= packedCopyWrapper;
00695         else /* Planar YUV or gray */
00696             c->swScale= planarCopyWrapper;
00697     }
00698 
00699     if (ARCH_BFIN)
00700         ff_bfin_get_unscaled_swscale(c);
00701     if (HAVE_ALTIVEC)
00702         ff_swscale_get_unscaled_altivec(c);
00703 }
00704 
00705 static void reset_ptr(const uint8_t* src[], int format)
00706 {
00707     if(!isALPHA(format))
00708         src[3]=NULL;
00709     if(!isPlanarYUV(format)) {
00710         src[3]=src[2]=NULL;
00711 
00712         if (!usePal(format))
00713             src[1]= NULL;
00714     }
00715 }
00716 
00717 static int check_image_pointers(uint8_t *data[4], enum PixelFormat pix_fmt,
00718                                 const int linesizes[4])
00719 {
00720     const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[pix_fmt];
00721     int i;
00722 
00723     for (i = 0; i < 4; i++) {
00724         int plane = desc->comp[i].plane;
00725         if (!data[plane] || !linesizes[plane])
00726             return 0;
00727     }
00728 
00729     return 1;
00730 }
00731 
00736 int sws_scale(SwsContext *c, const uint8_t* const src[], const int srcStride[], int srcSliceY,
00737               int srcSliceH, uint8_t* const dst[], const int dstStride[])
00738 {
00739     int i;
00740     const uint8_t* src2[4]= {src[0], src[1], src[2], src[3]};
00741     uint8_t* dst2[4]= {dst[0], dst[1], dst[2], dst[3]};
00742 
00743     // do not mess up sliceDir if we have a "trailing" 0-size slice
00744     if (srcSliceH == 0)
00745         return 0;
00746 
00747     if (!check_image_pointers(src, c->srcFormat, srcStride)) {
00748         av_log(c, AV_LOG_ERROR, "bad src image pointers\n");
00749         return 0;
00750     }
00751     if (!check_image_pointers(dst, c->dstFormat, dstStride)) {
00752         av_log(c, AV_LOG_ERROR, "bad dst image pointers\n");
00753         return 0;
00754     }
00755 
00756     if (c->sliceDir == 0 && srcSliceY != 0 && srcSliceY + srcSliceH != c->srcH) {
00757         av_log(c, AV_LOG_ERROR, "Slices start in the middle!\n");
00758         return 0;
00759     }
00760     if (c->sliceDir == 0) {
00761         if (srcSliceY == 0) c->sliceDir = 1; else c->sliceDir = -1;
00762     }
00763 
00764     if (usePal(c->srcFormat)) {
00765         for (i=0; i<256; i++) {
00766             int p, r, g, b,y,u,v;
00767             if(c->srcFormat == PIX_FMT_PAL8) {
00768                 p=((const uint32_t*)(src[1]))[i];
00769                 r= (p>>16)&0xFF;
00770                 g= (p>> 8)&0xFF;
00771                 b=  p     &0xFF;
00772             } else if(c->srcFormat == PIX_FMT_RGB8) {
00773                 r= (i>>5    )*36;
00774                 g= ((i>>2)&7)*36;
00775                 b= (i&3     )*85;
00776             } else if(c->srcFormat == PIX_FMT_BGR8) {
00777                 b= (i>>6    )*85;
00778                 g= ((i>>3)&7)*36;
00779                 r= (i&7     )*36;
00780             } else if(c->srcFormat == PIX_FMT_RGB4_BYTE) {
00781                 r= (i>>3    )*255;
00782                 g= ((i>>1)&3)*85;
00783                 b= (i&1     )*255;
00784             } else if(c->srcFormat == PIX_FMT_GRAY8 || c->srcFormat == PIX_FMT_Y400A) {
00785                 r = g = b = i;
00786             } else {
00787                 assert(c->srcFormat == PIX_FMT_BGR4_BYTE);
00788                 b= (i>>3    )*255;
00789                 g= ((i>>1)&3)*85;
00790                 r= (i&1     )*255;
00791             }
00792             y= av_clip_uint8((RY*r + GY*g + BY*b + ( 33<<(RGB2YUV_SHIFT-1)))>>RGB2YUV_SHIFT);
00793             u= av_clip_uint8((RU*r + GU*g + BU*b + (257<<(RGB2YUV_SHIFT-1)))>>RGB2YUV_SHIFT);
00794             v= av_clip_uint8((RV*r + GV*g + BV*b + (257<<(RGB2YUV_SHIFT-1)))>>RGB2YUV_SHIFT);
00795             c->pal_yuv[i]= y + (u<<8) + (v<<16);
00796 
00797             switch(c->dstFormat) {
00798             case PIX_FMT_BGR32:
00799 #if !HAVE_BIGENDIAN
00800             case PIX_FMT_RGB24:
00801 #endif
00802                 c->pal_rgb[i]=  r + (g<<8) + (b<<16);
00803                 break;
00804             case PIX_FMT_BGR32_1:
00805 #if HAVE_BIGENDIAN
00806             case PIX_FMT_BGR24:
00807 #endif
00808                 c->pal_rgb[i]= (r + (g<<8) + (b<<16)) << 8;
00809                 break;
00810             case PIX_FMT_RGB32_1:
00811 #if HAVE_BIGENDIAN
00812             case PIX_FMT_RGB24:
00813 #endif
00814                 c->pal_rgb[i]= (b + (g<<8) + (r<<16)) << 8;
00815                 break;
00816             case PIX_FMT_RGB32:
00817 #if !HAVE_BIGENDIAN
00818             case PIX_FMT_BGR24:
00819 #endif
00820             default:
00821                 c->pal_rgb[i]=  b + (g<<8) + (r<<16);
00822             }
00823         }
00824     }
00825 
00826     // copy strides, so they can safely be modified
00827     if (c->sliceDir == 1) {
00828         // slices go from top to bottom
00829         int srcStride2[4]= {srcStride[0], srcStride[1], srcStride[2], srcStride[3]};
00830         int dstStride2[4]= {dstStride[0], dstStride[1], dstStride[2], dstStride[3]};
00831 
00832         reset_ptr(src2, c->srcFormat);
00833         reset_ptr((const uint8_t**)dst2, c->dstFormat);
00834 
00835         /* reset slice direction at end of frame */
00836         if (srcSliceY + srcSliceH == c->srcH)
00837             c->sliceDir = 0;
00838 
00839         return c->swScale(c, src2, srcStride2, srcSliceY, srcSliceH, dst2, dstStride2);
00840     } else {
00841         // slices go from bottom to top => we flip the image internally
00842         int srcStride2[4]= {-srcStride[0], -srcStride[1], -srcStride[2], -srcStride[3]};
00843         int dstStride2[4]= {-dstStride[0], -dstStride[1], -dstStride[2], -dstStride[3]};
00844 
00845         src2[0] += (srcSliceH-1)*srcStride[0];
00846         if (!usePal(c->srcFormat))
00847             src2[1] += ((srcSliceH>>c->chrSrcVSubSample)-1)*srcStride[1];
00848         src2[2] += ((srcSliceH>>c->chrSrcVSubSample)-1)*srcStride[2];
00849         src2[3] += (srcSliceH-1)*srcStride[3];
00850         dst2[0] += ( c->dstH                      -1)*dstStride[0];
00851         dst2[1] += ((c->dstH>>c->chrDstVSubSample)-1)*dstStride[1];
00852         dst2[2] += ((c->dstH>>c->chrDstVSubSample)-1)*dstStride[2];
00853         dst2[3] += ( c->dstH                      -1)*dstStride[3];
00854 
00855         reset_ptr(src2, c->srcFormat);
00856         reset_ptr((const uint8_t**)dst2, c->dstFormat);
00857 
00858         /* reset slice direction at end of frame */
00859         if (!srcSliceY)
00860             c->sliceDir = 0;
00861 
00862         return c->swScale(c, src2, srcStride2, c->srcH-srcSliceY-srcSliceH, srcSliceH, dst2, dstStride2);
00863     }
00864 }
00865 
00866 /* Convert the palette to the same packed 32-bit format as the palette */
00867 void sws_convertPalette8ToPacked32(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette)
00868 {
00869     int i;
00870 
00871     for (i=0; i<num_pixels; i++)
00872         ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i]];
00873 }
00874 
00875 /* Palette format: ABCD -> dst format: ABC */
00876 void sws_convertPalette8ToPacked24(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette)
00877 {
00878     int i;
00879 
00880     for (i=0; i<num_pixels; i++) {
00881         //FIXME slow?
00882         dst[0]= palette[src[i]*4+0];
00883         dst[1]= palette[src[i]*4+1];
00884         dst[2]= palette[src[i]*4+2];
00885         dst+= 3;
00886     }
00887 }