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 <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
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_GRAY8A) {
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 av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_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 static void gbr24ptopacked24(const uint8_t* src[], int srcStride[], uint8_t* dst, int dstStride, int srcSliceH, int width)
00259 {
00260 int x, h, i;
00261 for (h = 0; h < srcSliceH; h++) {
00262 uint8_t *dest = dst + dstStride * h;
00263 for (x = 0; x < width; x++) {
00264 *dest++ = src[0][x];
00265 *dest++ = src[1][x];
00266 *dest++ = src[2][x];
00267 }
00268
00269 for (i = 0; i < 3; i++)
00270 src[i] += srcStride[i];
00271 }
00272 }
00273
00274 static void gbr24ptopacked32(const uint8_t* src[], int srcStride[], uint8_t* dst, int dstStride, int srcSliceH, int alpha_first, int width)
00275 {
00276 int x, h, i;
00277 for (h = 0; h < srcSliceH; h++) {
00278 uint8_t *dest = dst + dstStride * h;
00279
00280 if (alpha_first) {
00281 for (x = 0; x < width; x++) {
00282 *dest++ = 0xff;
00283 *dest++ = src[0][x];
00284 *dest++ = src[1][x];
00285 *dest++ = src[2][x];
00286 }
00287 } else {
00288 for (x = 0; x < width; x++) {
00289 *dest++ = src[0][x];
00290 *dest++ = src[1][x];
00291 *dest++ = src[2][x];
00292 *dest++ = 0xff;
00293 }
00294 }
00295
00296 for (i = 0; i < 3; i++)
00297 src[i] += srcStride[i];
00298 }
00299 }
00300
00301 static int planarRgbToRgbWrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00302 int srcSliceH, uint8_t* dst[], int dstStride[])
00303 {
00304 int alpha_first = 0;
00305 if (c->srcFormat != PIX_FMT_GBR24P) {
00306 av_log(c, AV_LOG_ERROR, "unsupported planar RGB conversion %s -> %s\n",
00307 av_get_pix_fmt_name(c->srcFormat), av_get_pix_fmt_name(c->dstFormat));
00308 return srcSliceH;
00309 }
00310
00311 switch (c->dstFormat) {
00312 case PIX_FMT_BGR24:
00313 gbr24ptopacked24((const uint8_t* []) {src[1], src[0], src[2]}, (int []) {srcStride[1], srcStride[0], srcStride[2]},
00314 dst[0] + srcSliceY * dstStride[0], dstStride[0], srcSliceH, c->srcW);
00315 break;
00316
00317 case PIX_FMT_RGB24:
00318 gbr24ptopacked24((const uint8_t* []) {src[2], src[0], src[1]}, (int []) {srcStride[2], srcStride[0], srcStride[1]},
00319 dst[0] + srcSliceY * dstStride[0], dstStride[0], srcSliceH, c->srcW);
00320 break;
00321
00322 case PIX_FMT_ARGB:
00323 alpha_first = 1;
00324 case PIX_FMT_RGBA:
00325 gbr24ptopacked32((const uint8_t* []) {src[2], src[0], src[1]}, (int []) {srcStride[2], srcStride[0], srcStride[1]},
00326 dst[0] + srcSliceY * dstStride[0], dstStride[0], srcSliceH, alpha_first, c->srcW);
00327 break;
00328
00329 case PIX_FMT_ABGR:
00330 alpha_first = 1;
00331 case PIX_FMT_BGRA:
00332 gbr24ptopacked32((const uint8_t* []) {src[1], src[0], src[2]}, (int []) {srcStride[1], srcStride[0], srcStride[2]},
00333 dst[0] + srcSliceY * dstStride[0], dstStride[0], srcSliceH, alpha_first, c->srcW);
00334 break;
00335
00336 default:
00337 av_log(c, AV_LOG_ERROR, "unsupported planar RGB conversion %s -> %s\n",
00338 av_get_pix_fmt_name(c->srcFormat), av_get_pix_fmt_name(c->dstFormat));
00339 }
00340
00341 return srcSliceH;
00342 }
00343
00344 #define isRGBA32(x) ( \
00345 (x) == PIX_FMT_ARGB \
00346 || (x) == PIX_FMT_RGBA \
00347 || (x) == PIX_FMT_BGRA \
00348 || (x) == PIX_FMT_ABGR \
00349 )
00350
00351
00352 static int rgbToRgbWrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00353 int srcSliceH, uint8_t* dst[], int dstStride[])
00354 {
00355 const enum PixelFormat srcFormat= c->srcFormat;
00356 const enum PixelFormat dstFormat= c->dstFormat;
00357 const int srcBpp= (c->srcFormatBpp + 7) >> 3;
00358 const int dstBpp= (c->dstFormatBpp + 7) >> 3;
00359 const int srcId= c->srcFormatBpp >> 2;
00360 const int dstId= c->dstFormatBpp >> 2;
00361 void (*conv)(const uint8_t *src, uint8_t *dst, int src_size)=NULL;
00362
00363 #define CONV_IS(src, dst) (srcFormat == PIX_FMT_##src && dstFormat == PIX_FMT_##dst)
00364
00365 if (isRGBA32(srcFormat) && isRGBA32(dstFormat)) {
00366 if ( CONV_IS(ABGR, RGBA)
00367 || CONV_IS(ARGB, BGRA)
00368 || CONV_IS(BGRA, ARGB)
00369 || CONV_IS(RGBA, ABGR)) conv = shuffle_bytes_3210;
00370 else if (CONV_IS(ABGR, ARGB)
00371 || CONV_IS(ARGB, ABGR)) conv = shuffle_bytes_0321;
00372 else if (CONV_IS(ABGR, BGRA)
00373 || CONV_IS(ARGB, RGBA)) conv = shuffle_bytes_1230;
00374 else if (CONV_IS(BGRA, RGBA)
00375 || CONV_IS(RGBA, BGRA)) conv = shuffle_bytes_2103;
00376 else if (CONV_IS(BGRA, ABGR)
00377 || CONV_IS(RGBA, ARGB)) conv = shuffle_bytes_3012;
00378 } else
00379
00380 if ( (isBGRinInt(srcFormat) && isBGRinInt(dstFormat))
00381 || (isRGBinInt(srcFormat) && isRGBinInt(dstFormat))) {
00382 switch(srcId | (dstId<<4)) {
00383 case 0x34: conv= rgb16to15; break;
00384 case 0x36: conv= rgb24to15; break;
00385 case 0x38: conv= rgb32to15; break;
00386 case 0x43: conv= rgb15to16; break;
00387 case 0x46: conv= rgb24to16; break;
00388 case 0x48: conv= rgb32to16; break;
00389 case 0x63: conv= rgb15to24; break;
00390 case 0x64: conv= rgb16to24; break;
00391 case 0x68: conv= rgb32to24; break;
00392 case 0x83: conv= rgb15to32; break;
00393 case 0x84: conv= rgb16to32; break;
00394 case 0x86: conv= rgb24to32; break;
00395 }
00396 } else if ( (isBGRinInt(srcFormat) && isRGBinInt(dstFormat))
00397 || (isRGBinInt(srcFormat) && isBGRinInt(dstFormat))) {
00398 switch(srcId | (dstId<<4)) {
00399 case 0x33: conv= rgb15tobgr15; break;
00400 case 0x34: conv= rgb16tobgr15; break;
00401 case 0x36: conv= rgb24tobgr15; break;
00402 case 0x38: conv= rgb32tobgr15; break;
00403 case 0x43: conv= rgb15tobgr16; break;
00404 case 0x44: conv= rgb16tobgr16; break;
00405 case 0x46: conv= rgb24tobgr16; break;
00406 case 0x48: conv= rgb32tobgr16; break;
00407 case 0x63: conv= rgb15tobgr24; break;
00408 case 0x64: conv= rgb16tobgr24; break;
00409 case 0x66: conv= rgb24tobgr24; break;
00410 case 0x68: conv= rgb32tobgr24; break;
00411 case 0x83: conv= rgb15tobgr32; break;
00412 case 0x84: conv= rgb16tobgr32; break;
00413 case 0x86: conv= rgb24tobgr32; break;
00414 }
00415 }
00416
00417 if (!conv) {
00418 av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n",
00419 av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_name(dstFormat));
00420 } else {
00421 const uint8_t *srcPtr= src[0];
00422 uint8_t *dstPtr= dst[0];
00423 if ((srcFormat == PIX_FMT_RGB32_1 || srcFormat == PIX_FMT_BGR32_1) && !isRGBA32(dstFormat))
00424 srcPtr += ALT32_CORR;
00425
00426 if ((dstFormat == PIX_FMT_RGB32_1 || dstFormat == PIX_FMT_BGR32_1) && !isRGBA32(srcFormat))
00427 dstPtr += ALT32_CORR;
00428
00429 if (dstStride[0]*srcBpp == srcStride[0]*dstBpp && srcStride[0] > 0 && !(srcStride[0] % srcBpp))
00430 conv(srcPtr, dstPtr + dstStride[0]*srcSliceY, srcSliceH*srcStride[0]);
00431 else {
00432 int i;
00433 dstPtr += dstStride[0]*srcSliceY;
00434
00435 for (i=0; i<srcSliceH; i++) {
00436 conv(srcPtr, dstPtr, c->srcW*srcBpp);
00437 srcPtr+= srcStride[0];
00438 dstPtr+= dstStride[0];
00439 }
00440 }
00441 }
00442 return srcSliceH;
00443 }
00444
00445 static int bgr24ToYv12Wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00446 int srcSliceH, uint8_t* dst[], int dstStride[])
00447 {
00448 rgb24toyv12(
00449 src[0],
00450 dst[0]+ srcSliceY *dstStride[0],
00451 dst[1]+(srcSliceY>>1)*dstStride[1],
00452 dst[2]+(srcSliceY>>1)*dstStride[2],
00453 c->srcW, srcSliceH,
00454 dstStride[0], dstStride[1], srcStride[0]);
00455 if (dst[3])
00456 fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
00457 return srcSliceH;
00458 }
00459
00460 static int yvu9ToYv12Wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00461 int srcSliceH, uint8_t* dst[], int dstStride[])
00462 {
00463 copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW,
00464 dst[0], dstStride[0]);
00465
00466 planar2x(src[1], dst[1] + dstStride[1]*(srcSliceY >> 1), c->chrSrcW,
00467 srcSliceH >> 2, srcStride[1], dstStride[1]);
00468 planar2x(src[2], dst[2] + dstStride[2]*(srcSliceY >> 1), c->chrSrcW,
00469 srcSliceH >> 2, srcStride[2], dstStride[2]);
00470 if (dst[3])
00471 fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
00472 return srcSliceH;
00473 }
00474
00475
00476 static int packedCopyWrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00477 int srcSliceH, uint8_t* dst[], int dstStride[])
00478 {
00479 if (dstStride[0]==srcStride[0] && srcStride[0] > 0)
00480 memcpy(dst[0] + dstStride[0]*srcSliceY, src[0], srcSliceH*dstStride[0]);
00481 else {
00482 int i;
00483 const uint8_t *srcPtr= src[0];
00484 uint8_t *dstPtr= dst[0] + dstStride[0]*srcSliceY;
00485 int length=0;
00486
00487
00488 while(length+c->srcW <= FFABS(dstStride[0])
00489 && length+c->srcW <= FFABS(srcStride[0])) length+= c->srcW;
00490 assert(length!=0);
00491
00492 for (i=0; i<srcSliceH; i++) {
00493 memcpy(dstPtr, srcPtr, length);
00494 srcPtr+= srcStride[0];
00495 dstPtr+= dstStride[0];
00496 }
00497 }
00498 return srcSliceH;
00499 }
00500
00501 #define DITHER_COPY(dst, dstStride, src, srcStride, bswap, dbswap)\
00502 uint16_t scale= dither_scale[dst_depth-1][src_depth-1];\
00503 int shift= src_depth-dst_depth + dither_scale[src_depth-2][dst_depth-1];\
00504 for (i = 0; i < height; i++) {\
00505 const uint8_t *dither= dithers[src_depth-9][i&7];\
00506 for (j = 0; j < length-7; j+=8){\
00507 dst[j+0] = dbswap((bswap(src[j+0]) + dither[0])*scale>>shift);\
00508 dst[j+1] = dbswap((bswap(src[j+1]) + dither[1])*scale>>shift);\
00509 dst[j+2] = dbswap((bswap(src[j+2]) + dither[2])*scale>>shift);\
00510 dst[j+3] = dbswap((bswap(src[j+3]) + dither[3])*scale>>shift);\
00511 dst[j+4] = dbswap((bswap(src[j+4]) + dither[4])*scale>>shift);\
00512 dst[j+5] = dbswap((bswap(src[j+5]) + dither[5])*scale>>shift);\
00513 dst[j+6] = dbswap((bswap(src[j+6]) + dither[6])*scale>>shift);\
00514 dst[j+7] = dbswap((bswap(src[j+7]) + dither[7])*scale>>shift);\
00515 }\
00516 for (; j < length; j++)\
00517 dst[j] = dbswap((bswap(src[j]) + dither[j&7])*scale>>shift);\
00518 dst += dstStride;\
00519 src += srcStride;\
00520 }
00521
00522
00523 static int planarCopyWrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
00524 int srcSliceH, uint8_t* dst[], int dstStride[])
00525 {
00526 int plane, i, j;
00527 for (plane=0; plane<4; plane++) {
00528 int length= (plane==0 || plane==3) ? c->srcW : -((-c->srcW )>>c->chrDstHSubSample);
00529 int y= (plane==0 || plane==3) ? srcSliceY: -((-srcSliceY)>>c->chrDstVSubSample);
00530 int height= (plane==0 || plane==3) ? srcSliceH: -((-srcSliceH)>>c->chrDstVSubSample);
00531 const uint8_t *srcPtr= src[plane];
00532 uint8_t *dstPtr= dst[plane] + dstStride[plane]*y;
00533 int shiftonly= plane==1 || plane==2 || (!c->srcRange && plane==0);
00534
00535 if (!dst[plane]) continue;
00536
00537 if (plane == 1 && !dst[2]) continue;
00538 if (!src[plane] || (plane == 1 && !src[2])) {
00539 if(is16BPS(c->dstFormat))
00540 length*=2;
00541 fillPlane(dst[plane], dstStride[plane], length, height, y, (plane==3) ? 255 : 128);
00542 } else {
00543 if(isNBPS(c->srcFormat) || isNBPS(c->dstFormat)
00544 || (is16BPS(c->srcFormat) != is16BPS(c->dstFormat))
00545 ) {
00546 const int src_depth = av_pix_fmt_descriptors[c->srcFormat].comp[plane].depth_minus1+1;
00547 const int dst_depth = av_pix_fmt_descriptors[c->dstFormat].comp[plane].depth_minus1+1;
00548 const uint16_t *srcPtr2 = (const uint16_t*)srcPtr;
00549 uint16_t *dstPtr2 = (uint16_t*)dstPtr;
00550
00551 if (dst_depth == 8) {
00552 if(isBE(c->srcFormat) == HAVE_BIGENDIAN){
00553 DITHER_COPY(dstPtr, dstStride[plane], srcPtr2, srcStride[plane]/2, , )
00554 } else {
00555 DITHER_COPY(dstPtr, dstStride[plane], srcPtr2, srcStride[plane]/2, av_bswap16, )
00556 }
00557 } else if (src_depth == 8) {
00558 for (i = 0; i < height; i++) {
00559 #define COPY816(w)\
00560 if(shiftonly){\
00561 for (j = 0; j < length; j++)\
00562 w(&dstPtr2[j], srcPtr[j]<<(dst_depth-8));\
00563 }else{\
00564 for (j = 0; j < length; j++)\
00565 w(&dstPtr2[j], (srcPtr[j]<<(dst_depth-8)) |\
00566 (srcPtr[j]>>(2*8-dst_depth)));\
00567 }
00568 if(isBE(c->dstFormat)){
00569 COPY816(AV_WB16)
00570 } else {
00571 COPY816(AV_WL16)
00572 }
00573 dstPtr2 += dstStride[plane]/2;
00574 srcPtr += srcStride[plane];
00575 }
00576 } else if (src_depth <= dst_depth) {
00577 for (i = 0; i < height; i++) {
00578 #define COPY_UP(r,w) \
00579 if(shiftonly){\
00580 for (j = 0; j < length; j++){ \
00581 unsigned int v= r(&srcPtr2[j]);\
00582 w(&dstPtr2[j], v<<(dst_depth-src_depth));\
00583 }\
00584 }else{\
00585 for (j = 0; j < length; j++){ \
00586 unsigned int v= r(&srcPtr2[j]);\
00587 w(&dstPtr2[j], (v<<(dst_depth-src_depth)) | \
00588 (v>>(2*src_depth-dst_depth)));\
00589 }\
00590 }
00591 if(isBE(c->srcFormat)){
00592 if(isBE(c->dstFormat)){
00593 COPY_UP(AV_RB16, AV_WB16)
00594 } else {
00595 COPY_UP(AV_RB16, AV_WL16)
00596 }
00597 } else {
00598 if(isBE(c->dstFormat)){
00599 COPY_UP(AV_RL16, AV_WB16)
00600 } else {
00601 COPY_UP(AV_RL16, AV_WL16)
00602 }
00603 }
00604 dstPtr2 += dstStride[plane]/2;
00605 srcPtr2 += srcStride[plane]/2;
00606 }
00607 } else {
00608 if(isBE(c->srcFormat) == HAVE_BIGENDIAN){
00609 if(isBE(c->dstFormat) == HAVE_BIGENDIAN){
00610 DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, , )
00611 } else {
00612 DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, , av_bswap16)
00613 }
00614 }else{
00615 if(isBE(c->dstFormat) == HAVE_BIGENDIAN){
00616 DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, av_bswap16, )
00617 } else {
00618 DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, av_bswap16, av_bswap16)
00619 }
00620 }
00621 }
00622 } else if(is16BPS(c->srcFormat) && is16BPS(c->dstFormat)
00623 && isBE(c->srcFormat) != isBE(c->dstFormat)) {
00624
00625 for (i=0; i<height; i++) {
00626 for (j=0; j<length; j++)
00627 ((uint16_t*)dstPtr)[j] = av_bswap16(((const uint16_t*)srcPtr)[j]);
00628 srcPtr+= srcStride[plane];
00629 dstPtr+= dstStride[plane];
00630 }
00631 } else if (dstStride[plane] == srcStride[plane] &&
00632 srcStride[plane] > 0 && srcStride[plane] == length) {
00633 memcpy(dst[plane] + dstStride[plane]*y, src[plane],
00634 height*dstStride[plane]);
00635 } else {
00636 if(is16BPS(c->srcFormat) && is16BPS(c->dstFormat))
00637 length*=2;
00638 for (i=0; i<height; i++) {
00639 memcpy(dstPtr, srcPtr, length);
00640 srcPtr+= srcStride[plane];
00641 dstPtr+= dstStride[plane];
00642 }
00643 }
00644 }
00645 }
00646 return srcSliceH;
00647 }
00648
00649 void ff_get_unscaled_swscale(SwsContext *c)
00650 {
00651 const enum PixelFormat srcFormat = c->srcFormat;
00652 const enum PixelFormat dstFormat = c->dstFormat;
00653 const int flags = c->flags;
00654 const int dstH = c->dstH;
00655 int needsDither;
00656
00657 needsDither= isAnyRGB(dstFormat)
00658 && c->dstFormatBpp < 24
00659 && (c->dstFormatBpp < c->srcFormatBpp || (!isAnyRGB(srcFormat)));
00660
00661
00662 if ((srcFormat == PIX_FMT_YUV420P || srcFormat == PIX_FMT_YUVA420P) && (dstFormat == PIX_FMT_NV12 || dstFormat == PIX_FMT_NV21)) {
00663 c->swScale= planarToNv12Wrapper;
00664 }
00665
00666 if ((srcFormat==PIX_FMT_YUV420P || srcFormat==PIX_FMT_YUV422P || srcFormat==PIX_FMT_YUVA420P) && isAnyRGB(dstFormat)
00667 && !(flags & SWS_ACCURATE_RND) && !(dstH&1)) {
00668 c->swScale= ff_yuv2rgb_get_func_ptr(c);
00669 }
00670
00671 if (srcFormat==PIX_FMT_YUV410P && (dstFormat==PIX_FMT_YUV420P || dstFormat==PIX_FMT_YUVA420P) && !(flags & SWS_BITEXACT)) {
00672 c->swScale= yvu9ToYv12Wrapper;
00673 }
00674
00675
00676 if (srcFormat==PIX_FMT_BGR24 && (dstFormat==PIX_FMT_YUV420P || dstFormat==PIX_FMT_YUVA420P) && !(flags & SWS_ACCURATE_RND))
00677 c->swScale= bgr24ToYv12Wrapper;
00678
00679
00680 if ( isAnyRGB(srcFormat)
00681 && isAnyRGB(dstFormat)
00682 && srcFormat != PIX_FMT_BGR8 && dstFormat != PIX_FMT_BGR8
00683 && srcFormat != PIX_FMT_RGB8 && dstFormat != PIX_FMT_RGB8
00684 && srcFormat != PIX_FMT_BGR4 && dstFormat != PIX_FMT_BGR4
00685 && srcFormat != PIX_FMT_RGB4 && dstFormat != PIX_FMT_RGB4
00686 && srcFormat != PIX_FMT_BGR4_BYTE && dstFormat != PIX_FMT_BGR4_BYTE
00687 && srcFormat != PIX_FMT_RGB4_BYTE && dstFormat != PIX_FMT_RGB4_BYTE
00688 && srcFormat != PIX_FMT_MONOBLACK && dstFormat != PIX_FMT_MONOBLACK
00689 && srcFormat != PIX_FMT_MONOWHITE && dstFormat != PIX_FMT_MONOWHITE
00690 && srcFormat != PIX_FMT_RGB48LE && dstFormat != PIX_FMT_RGB48LE
00691 && srcFormat != PIX_FMT_RGB48BE && dstFormat != PIX_FMT_RGB48BE
00692 && srcFormat != PIX_FMT_BGR48LE && dstFormat != PIX_FMT_BGR48LE
00693 && srcFormat != PIX_FMT_BGR48BE && dstFormat != PIX_FMT_BGR48BE
00694 && (!needsDither || (c->flags&(SWS_FAST_BILINEAR|SWS_POINT))))
00695 c->swScale= rgbToRgbWrapper;
00696
00697 #define isByteRGB(f) (\
00698 f == PIX_FMT_RGB32 ||\
00699 f == PIX_FMT_RGB32_1 ||\
00700 f == PIX_FMT_RGB24 ||\
00701 f == PIX_FMT_BGR32 ||\
00702 f == PIX_FMT_BGR32_1 ||\
00703 f == PIX_FMT_BGR24)
00704
00705 if (isAnyRGB(srcFormat) && isPlanar(srcFormat) && isByteRGB(dstFormat))
00706 c->swScale= planarRgbToRgbWrapper;
00707
00708 if (usePal(srcFormat) && isByteRGB(dstFormat))
00709 c->swScale= palToRgbWrapper;
00710
00711 if (srcFormat == PIX_FMT_YUV422P) {
00712 if (dstFormat == PIX_FMT_YUYV422)
00713 c->swScale= yuv422pToYuy2Wrapper;
00714 else if (dstFormat == PIX_FMT_UYVY422)
00715 c->swScale= yuv422pToUyvyWrapper;
00716 }
00717
00718
00719 if (c->flags&(SWS_FAST_BILINEAR|SWS_POINT)) {
00720
00721 if (srcFormat == PIX_FMT_YUV420P || srcFormat == PIX_FMT_YUVA420P) {
00722 if (dstFormat == PIX_FMT_YUYV422)
00723 c->swScale= planarToYuy2Wrapper;
00724 else if (dstFormat == PIX_FMT_UYVY422)
00725 c->swScale= planarToUyvyWrapper;
00726 }
00727 }
00728 if(srcFormat == PIX_FMT_YUYV422 && (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P))
00729 c->swScale= yuyvToYuv420Wrapper;
00730 if(srcFormat == PIX_FMT_UYVY422 && (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P))
00731 c->swScale= uyvyToYuv420Wrapper;
00732 if(srcFormat == PIX_FMT_YUYV422 && dstFormat == PIX_FMT_YUV422P)
00733 c->swScale= yuyvToYuv422Wrapper;
00734 if(srcFormat == PIX_FMT_UYVY422 && dstFormat == PIX_FMT_YUV422P)
00735 c->swScale= uyvyToYuv422Wrapper;
00736
00737
00738 if ( srcFormat == dstFormat
00739 || (srcFormat == PIX_FMT_YUVA420P && dstFormat == PIX_FMT_YUV420P)
00740 || (srcFormat == PIX_FMT_YUV420P && dstFormat == PIX_FMT_YUVA420P)
00741 || (isPlanarYUV(srcFormat) && isGray(dstFormat))
00742 || (isPlanarYUV(dstFormat) && isGray(srcFormat))
00743 || (isGray(dstFormat) && isGray(srcFormat))
00744 || (isPlanarYUV(srcFormat) && isPlanarYUV(dstFormat)
00745 && c->chrDstHSubSample == c->chrSrcHSubSample
00746 && c->chrDstVSubSample == c->chrSrcVSubSample
00747 && dstFormat != PIX_FMT_NV12 && dstFormat != PIX_FMT_NV21
00748 && srcFormat != PIX_FMT_NV12 && srcFormat != PIX_FMT_NV21))
00749 {
00750 if (isPacked(c->srcFormat))
00751 c->swScale= packedCopyWrapper;
00752 else
00753 c->swScale= planarCopyWrapper;
00754 }
00755
00756 if (ARCH_BFIN)
00757 ff_bfin_get_unscaled_swscale(c);
00758 if (HAVE_ALTIVEC)
00759 ff_swscale_get_unscaled_altivec(c);
00760 }
00761
00762 static void reset_ptr(const uint8_t* src[], int format)
00763 {
00764 if(!isALPHA(format))
00765 src[3]=NULL;
00766 if (!isPlanar(format)) {
00767 src[3]=src[2]=NULL;
00768
00769 if (!usePal(format))
00770 src[1]= NULL;
00771 }
00772 }
00773
00774 static int check_image_pointers(const uint8_t * const data[4], enum PixelFormat pix_fmt,
00775 const int linesizes[4])
00776 {
00777 const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[pix_fmt];
00778 int i;
00779
00780 for (i = 0; i < 4; i++) {
00781 int plane = desc->comp[i].plane;
00782 if (!data[plane] || !linesizes[plane])
00783 return 0;
00784 }
00785
00786 return 1;
00787 }
00788
00793 int attribute_align_arg sws_scale(struct SwsContext *c, const uint8_t* const srcSlice[],
00794 const int srcStride[], int srcSliceY, int srcSliceH,
00795 uint8_t* const dst[], const int dstStride[])
00796 {
00797 int i;
00798 const uint8_t* src2[4]= {srcSlice[0], srcSlice[1], srcSlice[2], srcSlice[3]};
00799 uint8_t* dst2[4]= {dst[0], dst[1], dst[2], dst[3]};
00800
00801
00802 if (srcSliceH == 0)
00803 return 0;
00804
00805 if (!check_image_pointers(srcSlice, c->srcFormat, srcStride)) {
00806 av_log(c, AV_LOG_ERROR, "bad src image pointers\n");
00807 return 0;
00808 }
00809 if (!check_image_pointers((const uint8_t* const*)dst, c->dstFormat, dstStride)) {
00810 av_log(c, AV_LOG_ERROR, "bad dst image pointers\n");
00811 return 0;
00812 }
00813
00814 if (c->sliceDir == 0 && srcSliceY != 0 && srcSliceY + srcSliceH != c->srcH) {
00815 av_log(c, AV_LOG_ERROR, "Slices start in the middle!\n");
00816 return 0;
00817 }
00818 if (c->sliceDir == 0) {
00819 if (srcSliceY == 0) c->sliceDir = 1; else c->sliceDir = -1;
00820 }
00821
00822 if (usePal(c->srcFormat)) {
00823 for (i=0; i<256; i++) {
00824 int p, r, g, b, y, u, v, a = 0xff;
00825 if(c->srcFormat == PIX_FMT_PAL8) {
00826 p=((const uint32_t*)(srcSlice[1]))[i];
00827 a= (p>>24)&0xFF;
00828 r= (p>>16)&0xFF;
00829 g= (p>> 8)&0xFF;
00830 b= p &0xFF;
00831 } else if(c->srcFormat == PIX_FMT_RGB8) {
00832 r= (i>>5 )*36;
00833 g= ((i>>2)&7)*36;
00834 b= (i&3 )*85;
00835 } else if(c->srcFormat == PIX_FMT_BGR8) {
00836 b= (i>>6 )*85;
00837 g= ((i>>3)&7)*36;
00838 r= (i&7 )*36;
00839 } else if(c->srcFormat == PIX_FMT_RGB4_BYTE) {
00840 r= (i>>3 )*255;
00841 g= ((i>>1)&3)*85;
00842 b= (i&1 )*255;
00843 } else if(c->srcFormat == PIX_FMT_GRAY8 || c->srcFormat == PIX_FMT_GRAY8A) {
00844 r = g = b = i;
00845 } else {
00846 assert(c->srcFormat == PIX_FMT_BGR4_BYTE);
00847 b= (i>>3 )*255;
00848 g= ((i>>1)&3)*85;
00849 r= (i&1 )*255;
00850 }
00851 y= av_clip_uint8((RY*r + GY*g + BY*b + ( 33<<(RGB2YUV_SHIFT-1)))>>RGB2YUV_SHIFT);
00852 u= av_clip_uint8((RU*r + GU*g + BU*b + (257<<(RGB2YUV_SHIFT-1)))>>RGB2YUV_SHIFT);
00853 v= av_clip_uint8((RV*r + GV*g + BV*b + (257<<(RGB2YUV_SHIFT-1)))>>RGB2YUV_SHIFT);
00854 c->pal_yuv[i]= y + (u<<8) + (v<<16) + (a<<24);
00855
00856 switch(c->dstFormat) {
00857 case PIX_FMT_BGR32:
00858 #if !HAVE_BIGENDIAN
00859 case PIX_FMT_RGB24:
00860 #endif
00861 c->pal_rgb[i]= r + (g<<8) + (b<<16) + (a<<24);
00862 break;
00863 case PIX_FMT_BGR32_1:
00864 #if HAVE_BIGENDIAN
00865 case PIX_FMT_BGR24:
00866 #endif
00867 c->pal_rgb[i]= a + (r<<8) + (g<<16) + (b<<24);
00868 break;
00869 case PIX_FMT_RGB32_1:
00870 #if HAVE_BIGENDIAN
00871 case PIX_FMT_RGB24:
00872 #endif
00873 c->pal_rgb[i]= a + (b<<8) + (g<<16) + (r<<24);
00874 break;
00875 case PIX_FMT_RGB32:
00876 #if !HAVE_BIGENDIAN
00877 case PIX_FMT_BGR24:
00878 #endif
00879 default:
00880 c->pal_rgb[i]= b + (g<<8) + (r<<16) + (a<<24);
00881 }
00882 }
00883 }
00884
00885
00886 if (c->sliceDir == 1) {
00887
00888 int srcStride2[4]= {srcStride[0], srcStride[1], srcStride[2], srcStride[3]};
00889 int dstStride2[4]= {dstStride[0], dstStride[1], dstStride[2], dstStride[3]};
00890
00891 reset_ptr(src2, c->srcFormat);
00892 reset_ptr((void*)dst2, c->dstFormat);
00893
00894
00895 if (srcSliceY + srcSliceH == c->srcH)
00896 c->sliceDir = 0;
00897
00898 return c->swScale(c, src2, srcStride2, srcSliceY, srcSliceH, dst2, dstStride2);
00899 } else {
00900
00901 int srcStride2[4]= {-srcStride[0], -srcStride[1], -srcStride[2], -srcStride[3]};
00902 int dstStride2[4]= {-dstStride[0], -dstStride[1], -dstStride[2], -dstStride[3]};
00903
00904 src2[0] += (srcSliceH-1)*srcStride[0];
00905 if (!usePal(c->srcFormat))
00906 src2[1] += ((srcSliceH>>c->chrSrcVSubSample)-1)*srcStride[1];
00907 src2[2] += ((srcSliceH>>c->chrSrcVSubSample)-1)*srcStride[2];
00908 src2[3] += (srcSliceH-1)*srcStride[3];
00909 dst2[0] += ( c->dstH -1)*dstStride[0];
00910 dst2[1] += ((c->dstH>>c->chrDstVSubSample)-1)*dstStride[1];
00911 dst2[2] += ((c->dstH>>c->chrDstVSubSample)-1)*dstStride[2];
00912 dst2[3] += ( c->dstH -1)*dstStride[3];
00913
00914 reset_ptr(src2, c->srcFormat);
00915 reset_ptr((void*)dst2, c->dstFormat);
00916
00917
00918 if (!srcSliceY)
00919 c->sliceDir = 0;
00920
00921 return c->swScale(c, src2, srcStride2, c->srcH-srcSliceY-srcSliceH, srcSliceH, dst2, dstStride2);
00922 }
00923 }
00924
00925
00926 void sws_convertPalette8ToPacked32(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette)
00927 {
00928 int i;
00929
00930 for (i=0; i<num_pixels; i++)
00931 ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i]];
00932 }
00933
00934
00935 void sws_convertPalette8ToPacked24(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette)
00936 {
00937 int i;
00938
00939 for (i=0; i<num_pixels; i++) {
00940
00941 dst[0]= palette[src[i]*4+0];
00942 dst[1]= palette[src[i]*4+1];
00943 dst[2]= palette[src[i]*4+2];
00944 dst+= 3;
00945 }
00946 }