2 * Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at>
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 #include "swscale_internal.h"
30 #include "libavutil/intreadwrite.h"
31 #include "libavutil/cpu.h"
32 #include "libavutil/avutil.h"
33 #include "libavutil/mathematics.h"
34 #include "libavutil/bswap.h"
35 #include "libavutil/pixdesc.h"
37 #define RGB2YUV_SHIFT 15
38 #define BY ( (int) (0.114 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
39 #define BV (-(int) (0.081 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
40 #define BU ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
41 #define GY ( (int) (0.587 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
42 #define GV (-(int) (0.419 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
43 #define GU (-(int) (0.331 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
44 #define RY ( (int) (0.299 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
45 #define RV ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
46 #define RU (-(int) (0.169 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
48 static void fillPlane(uint8_t *plane, int stride, int width, int height, int y,
52 uint8_t *ptr = plane + stride * y;
53 for (i = 0; i < height; i++) {
54 memset(ptr, val, width);
59 static void fillPlane16(uint8_t *plane, int stride, int width, int height, int y,
63 uint8_t *ptr = plane + stride * y;
64 int v = alpha ? -1 : (1<<bits);
65 for (i = 0; i < height; i++) {
66 for (j = 0; j < width; j++) {
73 static void copyPlane(const uint8_t *src, int srcStride,
74 int srcSliceY, int srcSliceH, int width,
75 uint8_t *dst, int dstStride)
77 dst += dstStride * srcSliceY;
78 if (dstStride == srcStride && srcStride > 0) {
79 memcpy(dst, src, srcSliceH * dstStride);
82 for (i = 0; i < srcSliceH; i++) {
83 memcpy(dst, src, width);
90 static int planarToNv12Wrapper(SwsContext *c, const uint8_t *src[],
91 int srcStride[], int srcSliceY,
92 int srcSliceH, uint8_t *dstParam[],
95 uint8_t *dst = dstParam[1] + dstStride[1] * srcSliceY / 2;
97 copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW,
98 dstParam[0], dstStride[0]);
100 if (c->dstFormat == PIX_FMT_NV12)
101 interleaveBytes(src[1], src[2], dst, c->srcW / 2, srcSliceH / 2,
102 srcStride[1], srcStride[2], dstStride[0]);
104 interleaveBytes(src[2], src[1], dst, c->srcW / 2, srcSliceH / 2,
105 srcStride[2], srcStride[1], dstStride[0]);
110 static int planarToYuy2Wrapper(SwsContext *c, const uint8_t *src[],
111 int srcStride[], int srcSliceY, int srcSliceH,
112 uint8_t *dstParam[], int dstStride[])
114 uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
116 yv12toyuy2(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
117 srcStride[1], dstStride[0]);
122 static int planarToUyvyWrapper(SwsContext *c, const uint8_t *src[],
123 int srcStride[], int srcSliceY, int srcSliceH,
124 uint8_t *dstParam[], int dstStride[])
126 uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
128 yv12touyvy(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
129 srcStride[1], dstStride[0]);
134 static int yuv422pToYuy2Wrapper(SwsContext *c, const uint8_t *src[],
135 int srcStride[], int srcSliceY, int srcSliceH,
136 uint8_t *dstParam[], int dstStride[])
138 uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
140 yuv422ptoyuy2(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
141 srcStride[1], dstStride[0]);
146 static int yuv422pToUyvyWrapper(SwsContext *c, const uint8_t *src[],
147 int srcStride[], int srcSliceY, int srcSliceH,
148 uint8_t *dstParam[], int dstStride[])
150 uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY;
152 yuv422ptouyvy(src[0], src[1], src[2], dst, c->srcW, srcSliceH, srcStride[0],
153 srcStride[1], dstStride[0]);
158 static int yuyvToYuv420Wrapper(SwsContext *c, const uint8_t *src[],
159 int srcStride[], int srcSliceY, int srcSliceH,
160 uint8_t *dstParam[], int dstStride[])
162 uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
163 uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY / 2;
164 uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY / 2;
166 yuyvtoyuv420(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
167 dstStride[1], srcStride[0]);
170 fillPlane(dstParam[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
175 static int yuyvToYuv422Wrapper(SwsContext *c, const uint8_t *src[],
176 int srcStride[], int srcSliceY, int srcSliceH,
177 uint8_t *dstParam[], int dstStride[])
179 uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
180 uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY;
181 uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY;
183 yuyvtoyuv422(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
184 dstStride[1], srcStride[0]);
189 static int uyvyToYuv420Wrapper(SwsContext *c, const uint8_t *src[],
190 int srcStride[], int srcSliceY, int srcSliceH,
191 uint8_t *dstParam[], int dstStride[])
193 uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
194 uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY / 2;
195 uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY / 2;
197 uyvytoyuv420(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
198 dstStride[1], srcStride[0]);
201 fillPlane(dstParam[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
206 static int uyvyToYuv422Wrapper(SwsContext *c, const uint8_t *src[],
207 int srcStride[], int srcSliceY, int srcSliceH,
208 uint8_t *dstParam[], int dstStride[])
210 uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY;
211 uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY;
212 uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY;
214 uyvytoyuv422(ydst, udst, vdst, src[0], c->srcW, srcSliceH, dstStride[0],
215 dstStride[1], srcStride[0]);
220 static void gray8aToPacked32(const uint8_t *src, uint8_t *dst, int num_pixels,
221 const uint8_t *palette)
224 for (i = 0; i < num_pixels; i++)
225 ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i << 1]] | (src[(i << 1) + 1] << 24);
228 static void gray8aToPacked32_1(const uint8_t *src, uint8_t *dst, int num_pixels,
229 const uint8_t *palette)
233 for (i = 0; i < num_pixels; i++)
234 ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i << 1]] | src[(i << 1) + 1];
237 static void gray8aToPacked24(const uint8_t *src, uint8_t *dst, int num_pixels,
238 const uint8_t *palette)
242 for (i = 0; i < num_pixels; i++) {
244 dst[0] = palette[src[i << 1] * 4 + 0];
245 dst[1] = palette[src[i << 1] * 4 + 1];
246 dst[2] = palette[src[i << 1] * 4 + 2];
251 static int packed_16bpc_bswap(SwsContext *c, const uint8_t *src[],
252 int srcStride[], int srcSliceY, int srcSliceH,
253 uint8_t *dst[], int dstStride[])
256 int srcstr = srcStride[0] >> 1;
257 int dststr = dstStride[0] >> 1;
258 uint16_t *dstPtr = (uint16_t *) dst[0];
259 const uint16_t *srcPtr = (const uint16_t *) src[0];
260 int min_stride = FFMIN(srcstr, dststr);
262 for (i = 0; i < srcSliceH; i++) {
263 for (j = 0; j < min_stride; j++) {
264 dstPtr[j] = av_bswap16(srcPtr[j]);
273 static int palToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[],
274 int srcSliceY, int srcSliceH, uint8_t *dst[],
277 const enum PixelFormat srcFormat = c->srcFormat;
278 const enum PixelFormat dstFormat = c->dstFormat;
279 void (*conv)(const uint8_t *src, uint8_t *dst, int num_pixels,
280 const uint8_t *palette) = NULL;
282 uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY;
283 const uint8_t *srcPtr = src[0];
285 if (srcFormat == PIX_FMT_GRAY8A) {
287 case PIX_FMT_RGB32 : conv = gray8aToPacked32; break;
288 case PIX_FMT_BGR32 : conv = gray8aToPacked32; break;
289 case PIX_FMT_BGR32_1: conv = gray8aToPacked32_1; break;
290 case PIX_FMT_RGB32_1: conv = gray8aToPacked32_1; break;
291 case PIX_FMT_RGB24 : conv = gray8aToPacked24; break;
292 case PIX_FMT_BGR24 : conv = gray8aToPacked24; break;
294 } else if (usePal(srcFormat)) {
296 case PIX_FMT_RGB32 : conv = sws_convertPalette8ToPacked32; break;
297 case PIX_FMT_BGR32 : conv = sws_convertPalette8ToPacked32; break;
298 case PIX_FMT_BGR32_1: conv = sws_convertPalette8ToPacked32; break;
299 case PIX_FMT_RGB32_1: conv = sws_convertPalette8ToPacked32; break;
300 case PIX_FMT_RGB24 : conv = sws_convertPalette8ToPacked24; break;
301 case PIX_FMT_BGR24 : conv = sws_convertPalette8ToPacked24; break;
306 av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n",
307 av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_name(dstFormat));
309 for (i = 0; i < srcSliceH; i++) {
310 conv(srcPtr, dstPtr, c->srcW, (uint8_t *) c->pal_rgb);
311 srcPtr += srcStride[0];
312 dstPtr += dstStride[0];
319 static void gbr24ptopacked24(const uint8_t* src[], int srcStride[], uint8_t* dst, int dstStride, int srcSliceH, int width)
322 for (h = 0; h < srcSliceH; h++) {
323 uint8_t *dest = dst + dstStride * h;
324 for (x = 0; x < width; x++) {
330 for (i = 0; i < 3; i++)
331 src[i] += srcStride[i];
335 static void gbr24ptopacked32(const uint8_t* src[], int srcStride[], uint8_t* dst, int dstStride, int srcSliceH, int alpha_first, int width)
338 for (h = 0; h < srcSliceH; h++) {
339 uint8_t *dest = dst + dstStride * h;
342 for (x = 0; x < width; x++) {
349 for (x = 0; x < width; x++) {
357 for (i = 0; i < 3; i++)
358 src[i] += srcStride[i];
362 static int planarRgbToRgbWrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
363 int srcSliceH, uint8_t* dst[], int dstStride[])
366 if (c->srcFormat != PIX_FMT_GBR24P) {
367 av_log(c, AV_LOG_ERROR, "unsupported planar RGB conversion %s -> %s\n",
368 av_get_pix_fmt_name(c->srcFormat), av_get_pix_fmt_name(c->dstFormat));
372 switch (c->dstFormat) {
374 gbr24ptopacked24((const uint8_t* []) {src[1], src[0], src[2]}, (int []) {srcStride[1], srcStride[0], srcStride[2]},
375 dst[0] + srcSliceY * dstStride[0], dstStride[0], srcSliceH, c->srcW);
379 gbr24ptopacked24((const uint8_t* []) {src[2], src[0], src[1]}, (int []) {srcStride[2], srcStride[0], srcStride[1]},
380 dst[0] + srcSliceY * dstStride[0], dstStride[0], srcSliceH, c->srcW);
386 gbr24ptopacked32((const uint8_t* []) {src[2], src[0], src[1]}, (int []) {srcStride[2], srcStride[0], srcStride[1]},
387 dst[0] + srcSliceY * dstStride[0], dstStride[0], srcSliceH, alpha_first, c->srcW);
393 gbr24ptopacked32((const uint8_t* []) {src[1], src[0], src[2]}, (int []) {srcStride[1], srcStride[0], srcStride[2]},
394 dst[0] + srcSliceY * dstStride[0], dstStride[0], srcSliceH, alpha_first, c->srcW);
398 av_log(c, AV_LOG_ERROR, "unsupported planar RGB conversion %s -> %s\n",
399 av_get_pix_fmt_name(c->srcFormat), av_get_pix_fmt_name(c->dstFormat));
405 #define isRGBA32(x) ( \
406 (x) == PIX_FMT_ARGB \
407 || (x) == PIX_FMT_RGBA \
408 || (x) == PIX_FMT_BGRA \
409 || (x) == PIX_FMT_ABGR \
412 /* {RGB,BGR}{15,16,24,32,32_1} -> {RGB,BGR}{15,16,24,32} */
413 typedef void (* rgbConvFn) (const uint8_t *, uint8_t *, int);
414 static rgbConvFn findRgbConvFn(SwsContext *c)
416 const enum PixelFormat srcFormat = c->srcFormat;
417 const enum PixelFormat dstFormat = c->dstFormat;
418 const int srcId = c->srcFormatBpp;
419 const int dstId = c->dstFormatBpp;
420 rgbConvFn conv = NULL;
422 #define IS_NOT_NE(bpp, fmt) \
423 (((bpp + 7) >> 3) == 2 && \
424 (!(av_pix_fmt_descriptors[fmt].flags & PIX_FMT_BE) != !HAVE_BIGENDIAN))
426 /* if this is non-native rgb444/555/565, don't handle it here. */
427 if (IS_NOT_NE(srcId, srcFormat) || IS_NOT_NE(dstId, dstFormat))
430 #define CONV_IS(src, dst) (srcFormat == PIX_FMT_##src && dstFormat == PIX_FMT_##dst)
432 if (isRGBA32(srcFormat) && isRGBA32(dstFormat)) {
433 if ( CONV_IS(ABGR, RGBA)
434 || CONV_IS(ARGB, BGRA)
435 || CONV_IS(BGRA, ARGB)
436 || CONV_IS(RGBA, ABGR)) conv = shuffle_bytes_3210;
437 else if (CONV_IS(ABGR, ARGB)
438 || CONV_IS(ARGB, ABGR)) conv = shuffle_bytes_0321;
439 else if (CONV_IS(ABGR, BGRA)
440 || CONV_IS(ARGB, RGBA)) conv = shuffle_bytes_1230;
441 else if (CONV_IS(BGRA, RGBA)
442 || CONV_IS(RGBA, BGRA)) conv = shuffle_bytes_2103;
443 else if (CONV_IS(BGRA, ABGR)
444 || CONV_IS(RGBA, ARGB)) conv = shuffle_bytes_3012;
447 if ((isBGRinInt(srcFormat) && isBGRinInt(dstFormat)) ||
448 (isRGBinInt(srcFormat) && isRGBinInt(dstFormat))) {
449 switch (srcId | (dstId << 16)) {
450 case 0x000F000C: conv = rgb12to15; break;
451 case 0x000F0010: conv = rgb16to15; break;
452 case 0x000F0018: conv = rgb24to15; break;
453 case 0x000F0020: conv = rgb32to15; break;
454 case 0x0010000F: conv = rgb15to16; break;
455 case 0x00100018: conv = rgb24to16; break;
456 case 0x00100020: conv = rgb32to16; break;
457 case 0x0018000F: conv = rgb15to24; break;
458 case 0x00180010: conv = rgb16to24; break;
459 case 0x00180020: conv = rgb32to24; break;
460 case 0x0020000F: conv = rgb15to32; break;
461 case 0x00200010: conv = rgb16to32; break;
462 case 0x00200018: conv = rgb24to32; break;
464 } else if ((isBGRinInt(srcFormat) && isRGBinInt(dstFormat)) ||
465 (isRGBinInt(srcFormat) && isBGRinInt(dstFormat))) {
466 switch (srcId | (dstId << 16)) {
467 case 0x000C000C: conv = rgb12tobgr12; break;
468 case 0x000F000F: conv = rgb15tobgr15; break;
469 case 0x000F0010: conv = rgb16tobgr15; break;
470 case 0x000F0018: conv = rgb24tobgr15; break;
471 case 0x000F0020: conv = rgb32tobgr15; break;
472 case 0x0010000F: conv = rgb15tobgr16; break;
473 case 0x00100010: conv = rgb16tobgr16; break;
474 case 0x00100018: conv = rgb24tobgr16; break;
475 case 0x00100020: conv = rgb32tobgr16; break;
476 case 0x0018000F: conv = rgb15tobgr24; break;
477 case 0x00180010: conv = rgb16tobgr24; break;
478 case 0x00180018: conv = rgb24tobgr24; break;
479 case 0x00180020: conv = rgb32tobgr24; break;
480 case 0x0020000F: conv = rgb15tobgr32; break;
481 case 0x00200010: conv = rgb16tobgr32; break;
482 case 0x00200018: conv = rgb24tobgr32; break;
489 /* {RGB,BGR}{15,16,24,32,32_1} -> {RGB,BGR}{15,16,24,32} */
490 static int rgbToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[],
491 int srcSliceY, int srcSliceH, uint8_t *dst[],
495 const enum PixelFormat srcFormat = c->srcFormat;
496 const enum PixelFormat dstFormat = c->dstFormat;
497 const int srcBpp = (c->srcFormatBpp + 7) >> 3;
498 const int dstBpp = (c->dstFormatBpp + 7) >> 3;
499 rgbConvFn conv = findRgbConvFn(c);
502 av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n",
503 av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_name(dstFormat));
505 const uint8_t *srcPtr = src[0];
506 uint8_t *dstPtr = dst[0];
507 if ((srcFormat == PIX_FMT_RGB32_1 || srcFormat == PIX_FMT_BGR32_1) &&
508 !isRGBA32(dstFormat))
509 srcPtr += ALT32_CORR;
511 if ((dstFormat == PIX_FMT_RGB32_1 || dstFormat == PIX_FMT_BGR32_1) &&
512 !isRGBA32(srcFormat))
513 dstPtr += ALT32_CORR;
515 if (dstStride[0] * srcBpp == srcStride[0] * dstBpp && srcStride[0] > 0 &&
516 !(srcStride[0] % srcBpp))
517 conv(srcPtr, dstPtr + dstStride[0] * srcSliceY,
518 srcSliceH * srcStride[0]);
521 dstPtr += dstStride[0] * srcSliceY;
523 for (i = 0; i < srcSliceH; i++) {
524 conv(srcPtr, dstPtr, c->srcW * srcBpp);
525 srcPtr += srcStride[0];
526 dstPtr += dstStride[0];
533 static int bgr24ToYv12Wrapper(SwsContext *c, const uint8_t *src[],
534 int srcStride[], int srcSliceY, int srcSliceH,
535 uint8_t *dst[], int dstStride[])
539 dst[0] + srcSliceY * dstStride[0],
540 dst[1] + (srcSliceY >> 1) * dstStride[1],
541 dst[2] + (srcSliceY >> 1) * dstStride[2],
543 dstStride[0], dstStride[1], srcStride[0]);
545 fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
549 static int yvu9ToYv12Wrapper(SwsContext *c, const uint8_t *src[],
550 int srcStride[], int srcSliceY, int srcSliceH,
551 uint8_t *dst[], int dstStride[])
553 copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW,
554 dst[0], dstStride[0]);
556 planar2x(src[1], dst[1] + dstStride[1] * (srcSliceY >> 1), c->chrSrcW,
557 srcSliceH >> 2, srcStride[1], dstStride[1]);
558 planar2x(src[2], dst[2] + dstStride[2] * (srcSliceY >> 1), c->chrSrcW,
559 srcSliceH >> 2, srcStride[2], dstStride[2]);
561 fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
565 /* unscaled copy like stuff (assumes nearly identical formats) */
566 static int packedCopyWrapper(SwsContext *c, const uint8_t *src[],
567 int srcStride[], int srcSliceY, int srcSliceH,
568 uint8_t *dst[], int dstStride[])
570 if (dstStride[0] == srcStride[0] && srcStride[0] > 0)
571 memcpy(dst[0] + dstStride[0] * srcSliceY, src[0], srcSliceH * dstStride[0]);
574 const uint8_t *srcPtr = src[0];
575 uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY;
578 /* universal length finder */
579 while (length + c->srcW <= FFABS(dstStride[0]) &&
580 length + c->srcW <= FFABS(srcStride[0]))
584 for (i = 0; i < srcSliceH; i++) {
585 memcpy(dstPtr, srcPtr, length);
586 srcPtr += srcStride[0];
587 dstPtr += dstStride[0];
593 #define DITHER_COPY(dst, dstStride, src, srcStride, bswap, dbswap)\
594 uint16_t scale= dither_scale[dst_depth-1][src_depth-1];\
595 int shift= src_depth-dst_depth + dither_scale[src_depth-2][dst_depth-1];\
596 for (i = 0; i < height; i++) {\
597 const uint8_t *dither= dithers[src_depth-9][i&7];\
598 for (j = 0; j < length-7; j+=8){\
599 dst[j+0] = dbswap((bswap(src[j+0]) + dither[0])*scale>>shift);\
600 dst[j+1] = dbswap((bswap(src[j+1]) + dither[1])*scale>>shift);\
601 dst[j+2] = dbswap((bswap(src[j+2]) + dither[2])*scale>>shift);\
602 dst[j+3] = dbswap((bswap(src[j+3]) + dither[3])*scale>>shift);\
603 dst[j+4] = dbswap((bswap(src[j+4]) + dither[4])*scale>>shift);\
604 dst[j+5] = dbswap((bswap(src[j+5]) + dither[5])*scale>>shift);\
605 dst[j+6] = dbswap((bswap(src[j+6]) + dither[6])*scale>>shift);\
606 dst[j+7] = dbswap((bswap(src[j+7]) + dither[7])*scale>>shift);\
608 for (; j < length; j++)\
609 dst[j] = dbswap((bswap(src[j]) + dither[j&7])*scale>>shift);\
614 static int planarCopyWrapper(SwsContext *c, const uint8_t *src[],
615 int srcStride[], int srcSliceY, int srcSliceH,
616 uint8_t *dst[], int dstStride[])
619 for (plane = 0; plane < 4; plane++) {
620 int length = (plane == 0 || plane == 3) ? c->srcW : -((-c->srcW ) >> c->chrDstHSubSample);
621 int y = (plane == 0 || plane == 3) ? srcSliceY: -((-srcSliceY) >> c->chrDstVSubSample);
622 int height = (plane == 0 || plane == 3) ? srcSliceH: -((-srcSliceH) >> c->chrDstVSubSample);
623 const uint8_t *srcPtr = src[plane];
624 uint8_t *dstPtr = dst[plane] + dstStride[plane] * y;
625 int shiftonly= plane==1 || plane==2 || (!c->srcRange && plane==0);
629 // ignore palette for GRAY8
630 if (plane == 1 && !dst[2]) continue;
631 if (!src[plane] || (plane == 1 && !src[2])) {
632 if (is16BPS(c->dstFormat) || isNBPS(c->dstFormat)) {
633 fillPlane16(dst[plane], dstStride[plane], length, height, y,
634 plane == 3, av_pix_fmt_descriptors[c->dstFormat].comp[plane].depth_minus1);
636 fillPlane(dst[plane], dstStride[plane], length, height, y,
637 (plane == 3) ? 255 : 128);
640 if(isNBPS(c->srcFormat) || isNBPS(c->dstFormat)
641 || (is16BPS(c->srcFormat) != is16BPS(c->dstFormat))
643 const int src_depth = av_pix_fmt_descriptors[c->srcFormat].comp[plane].depth_minus1 + 1;
644 const int dst_depth = av_pix_fmt_descriptors[c->dstFormat].comp[plane].depth_minus1 + 1;
645 const uint16_t *srcPtr2 = (const uint16_t *) srcPtr;
646 uint16_t *dstPtr2 = (uint16_t*)dstPtr;
648 if (dst_depth == 8) {
649 if(isBE(c->srcFormat) == HAVE_BIGENDIAN){
650 DITHER_COPY(dstPtr, dstStride[plane], srcPtr2, srcStride[plane]/2, , )
652 DITHER_COPY(dstPtr, dstStride[plane], srcPtr2, srcStride[plane]/2, av_bswap16, )
654 } else if (src_depth == 8) {
655 for (i = 0; i < height; i++) {
658 for (j = 0; j < length; j++)\
659 w(&dstPtr2[j], srcPtr[j]<<(dst_depth-8));\
661 for (j = 0; j < length; j++)\
662 w(&dstPtr2[j], (srcPtr[j]<<(dst_depth-8)) |\
663 (srcPtr[j]>>(2*8-dst_depth)));\
665 if(isBE(c->dstFormat)){
670 dstPtr2 += dstStride[plane]/2;
671 srcPtr += srcStride[plane];
673 } else if (src_depth <= dst_depth) {
674 for (i = 0; i < height; i++) {
675 #define COPY_UP(r,w) \
677 for (j = 0; j < length; j++){ \
678 unsigned int v= r(&srcPtr2[j]);\
679 w(&dstPtr2[j], v<<(dst_depth-src_depth));\
682 for (j = 0; j < length; j++){ \
683 unsigned int v= r(&srcPtr2[j]);\
684 w(&dstPtr2[j], (v<<(dst_depth-src_depth)) | \
685 (v>>(2*src_depth-dst_depth)));\
688 if(isBE(c->srcFormat)){
689 if(isBE(c->dstFormat)){
690 COPY_UP(AV_RB16, AV_WB16)
692 COPY_UP(AV_RB16, AV_WL16)
695 if(isBE(c->dstFormat)){
696 COPY_UP(AV_RL16, AV_WB16)
698 COPY_UP(AV_RL16, AV_WL16)
701 dstPtr2 += dstStride[plane]/2;
702 srcPtr2 += srcStride[plane]/2;
705 if(isBE(c->srcFormat) == HAVE_BIGENDIAN){
706 if(isBE(c->dstFormat) == HAVE_BIGENDIAN){
707 DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, , )
709 DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, , av_bswap16)
712 if(isBE(c->dstFormat) == HAVE_BIGENDIAN){
713 DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, av_bswap16, )
715 DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, av_bswap16, av_bswap16)
719 } else if (is16BPS(c->srcFormat) && is16BPS(c->dstFormat) &&
720 isBE(c->srcFormat) != isBE(c->dstFormat)) {
722 for (i = 0; i < height; i++) {
723 for (j = 0; j < length; j++)
724 ((uint16_t *) dstPtr)[j] = av_bswap16(((const uint16_t *) srcPtr)[j]);
725 srcPtr += srcStride[plane];
726 dstPtr += dstStride[plane];
728 } else if (dstStride[plane] == srcStride[plane] &&
729 srcStride[plane] > 0 && srcStride[plane] == length) {
730 memcpy(dst[plane] + dstStride[plane] * y, src[plane],
731 height * dstStride[plane]);
733 if (is16BPS(c->srcFormat) && is16BPS(c->dstFormat))
735 else if (!av_pix_fmt_descriptors[c->srcFormat].comp[0].depth_minus1)
736 length >>= 3; // monowhite/black
737 for (i = 0; i < height; i++) {
738 memcpy(dstPtr, srcPtr, length);
739 srcPtr += srcStride[plane];
740 dstPtr += dstStride[plane];
749 #define IS_DIFFERENT_ENDIANESS(src_fmt, dst_fmt, pix_fmt) \
750 ((src_fmt == pix_fmt ## BE && dst_fmt == pix_fmt ## LE) || \
751 (src_fmt == pix_fmt ## LE && dst_fmt == pix_fmt ## BE))
754 void ff_get_unscaled_swscale(SwsContext *c)
756 const enum PixelFormat srcFormat = c->srcFormat;
757 const enum PixelFormat dstFormat = c->dstFormat;
758 const int flags = c->flags;
759 const int dstH = c->dstH;
762 needsDither = isAnyRGB(dstFormat) &&
763 c->dstFormatBpp < 24 &&
764 (c->dstFormatBpp < c->srcFormatBpp || (!isAnyRGB(srcFormat)));
767 if ((srcFormat == PIX_FMT_YUV420P || srcFormat == PIX_FMT_YUVA420P) &&
768 (dstFormat == PIX_FMT_NV12 || dstFormat == PIX_FMT_NV21)) {
769 c->swScale = planarToNv12Wrapper;
772 if ((srcFormat == PIX_FMT_YUV420P || srcFormat == PIX_FMT_YUV422P ||
773 srcFormat == PIX_FMT_YUVA420P) && isAnyRGB(dstFormat) &&
774 !(flags & SWS_ACCURATE_RND) && !(dstH & 1)) {
775 c->swScale = ff_yuv2rgb_get_func_ptr(c);
778 if (srcFormat == PIX_FMT_YUV410P &&
779 (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P) &&
780 !(flags & SWS_BITEXACT)) {
781 c->swScale = yvu9ToYv12Wrapper;
785 if (srcFormat == PIX_FMT_BGR24 &&
786 (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P) &&
787 !(flags & SWS_ACCURATE_RND))
788 c->swScale = bgr24ToYv12Wrapper;
790 /* RGB/BGR -> RGB/BGR (no dither needed forms) */
791 if (isAnyRGB(srcFormat) && isAnyRGB(dstFormat) && findRgbConvFn(c)
792 && (!needsDither || (c->flags&(SWS_FAST_BILINEAR|SWS_POINT))))
793 c->swScale= rgbToRgbWrapper;
795 #define isByteRGB(f) (\
796 f == PIX_FMT_RGB32 ||\
797 f == PIX_FMT_RGB32_1 ||\
798 f == PIX_FMT_RGB24 ||\
799 f == PIX_FMT_BGR32 ||\
800 f == PIX_FMT_BGR32_1 ||\
803 if (isAnyRGB(srcFormat) && isPlanar(srcFormat) && isByteRGB(dstFormat))
804 c->swScale= planarRgbToRgbWrapper;
806 /* bswap 16 bits per pixel/component packed formats */
807 if (IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_BGR444) ||
808 IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_BGR48) ||
809 IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_BGR555) ||
810 IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_BGR565) ||
811 IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_GRAY16) ||
812 IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_RGB444) ||
813 IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_RGB48) ||
814 IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_RGB555) ||
815 IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, PIX_FMT_RGB565))
816 c->swScale = packed_16bpc_bswap;
818 if (usePal(srcFormat) && isByteRGB(dstFormat))
819 c->swScale = palToRgbWrapper;
821 if (srcFormat == PIX_FMT_YUV422P) {
822 if (dstFormat == PIX_FMT_YUYV422)
823 c->swScale = yuv422pToYuy2Wrapper;
824 else if (dstFormat == PIX_FMT_UYVY422)
825 c->swScale = yuv422pToUyvyWrapper;
828 /* LQ converters if -sws 0 or -sws 4*/
829 if (c->flags&(SWS_FAST_BILINEAR|SWS_POINT)) {
831 if (srcFormat == PIX_FMT_YUV420P || srcFormat == PIX_FMT_YUVA420P) {
832 if (dstFormat == PIX_FMT_YUYV422)
833 c->swScale = planarToYuy2Wrapper;
834 else if (dstFormat == PIX_FMT_UYVY422)
835 c->swScale = planarToUyvyWrapper;
838 if (srcFormat == PIX_FMT_YUYV422 &&
839 (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P))
840 c->swScale = yuyvToYuv420Wrapper;
841 if (srcFormat == PIX_FMT_UYVY422 &&
842 (dstFormat == PIX_FMT_YUV420P || dstFormat == PIX_FMT_YUVA420P))
843 c->swScale = uyvyToYuv420Wrapper;
844 if (srcFormat == PIX_FMT_YUYV422 && dstFormat == PIX_FMT_YUV422P)
845 c->swScale = yuyvToYuv422Wrapper;
846 if (srcFormat == PIX_FMT_UYVY422 && dstFormat == PIX_FMT_YUV422P)
847 c->swScale = uyvyToYuv422Wrapper;
849 #define isPlanarGray(x) (isGray(x) && (x) != PIX_FMT_GRAY8A)
851 if ( srcFormat == dstFormat ||
852 (srcFormat == PIX_FMT_YUVA420P && dstFormat == PIX_FMT_YUV420P) ||
853 (srcFormat == PIX_FMT_YUV420P && dstFormat == PIX_FMT_YUVA420P) ||
854 (isPlanarYUV(srcFormat) && isPlanarGray(dstFormat)) ||
855 (isPlanarYUV(dstFormat) && isPlanarGray(srcFormat)) ||
856 (isPlanarGray(dstFormat) && isPlanarGray(srcFormat)) ||
857 (isPlanarYUV(srcFormat) && isPlanarYUV(dstFormat) &&
858 c->chrDstHSubSample == c->chrSrcHSubSample &&
859 c->chrDstVSubSample == c->chrSrcVSubSample &&
860 dstFormat != PIX_FMT_NV12 && dstFormat != PIX_FMT_NV21 &&
861 srcFormat != PIX_FMT_NV12 && srcFormat != PIX_FMT_NV21))
863 if (isPacked(c->srcFormat))
864 c->swScale = packedCopyWrapper;
865 else /* Planar YUV or gray */
866 c->swScale = planarCopyWrapper;
870 ff_bfin_get_unscaled_swscale(c);
872 ff_swscale_get_unscaled_altivec(c);
875 static void reset_ptr(const uint8_t *src[], int format)
877 if (!isALPHA(format))
879 if (!isPlanar(format)) {
880 src[3] = src[2] = NULL;
887 static int check_image_pointers(const uint8_t * const data[4], enum PixelFormat pix_fmt,
888 const int linesizes[4])
890 const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[pix_fmt];
893 for (i = 0; i < 4; i++) {
894 int plane = desc->comp[i].plane;
895 if (!data[plane] || !linesizes[plane])
903 * swscale wrapper, so we don't need to export the SwsContext.
904 * Assumes planar YUV to be in YUV order instead of YVU.
906 int attribute_align_arg sws_scale(struct SwsContext *c,
907 const uint8_t * const srcSlice[],
908 const int srcStride[], int srcSliceY,
909 int srcSliceH, uint8_t *const dst[],
910 const int dstStride[])
913 const uint8_t *src2[4] = { srcSlice[0], srcSlice[1], srcSlice[2], srcSlice[3] };
914 uint8_t *dst2[4] = { dst[0], dst[1], dst[2], dst[3] };
915 uint8_t *rgb0_tmp = NULL;
917 // do not mess up sliceDir if we have a "trailing" 0-size slice
921 if (!check_image_pointers(srcSlice, c->srcFormat, srcStride)) {
922 av_log(c, AV_LOG_ERROR, "bad src image pointers\n");
925 if (!check_image_pointers((const uint8_t* const*)dst, c->dstFormat, dstStride)) {
926 av_log(c, AV_LOG_ERROR, "bad dst image pointers\n");
930 if (c->sliceDir == 0 && srcSliceY != 0 && srcSliceY + srcSliceH != c->srcH) {
931 av_log(c, AV_LOG_ERROR, "Slices start in the middle!\n");
934 if (c->sliceDir == 0) {
935 if (srcSliceY == 0) c->sliceDir = 1; else c->sliceDir = -1;
938 if (usePal(c->srcFormat)) {
939 for (i = 0; i < 256; i++) {
940 int p, r, g, b, y, u, v, a = 0xff;
941 if (c->srcFormat == PIX_FMT_PAL8) {
942 p = ((const uint32_t *)(srcSlice[1]))[i];
943 a = (p >> 24) & 0xFF;
944 r = (p >> 16) & 0xFF;
947 } else if (c->srcFormat == PIX_FMT_RGB8) {
949 g = ((i >> 2) & 7) * 36;
951 } else if (c->srcFormat == PIX_FMT_BGR8) {
953 g = ((i >> 3) & 7) * 36;
955 } else if (c->srcFormat == PIX_FMT_RGB4_BYTE) {
956 r = ( i >> 3 ) * 255;
957 g = ((i >> 1) & 3) * 85;
959 } else if (c->srcFormat == PIX_FMT_GRAY8 || c->srcFormat == PIX_FMT_GRAY8A) {
962 assert(c->srcFormat == PIX_FMT_BGR4_BYTE);
963 b = ( i >> 3 ) * 255;
964 g = ((i >> 1) & 3) * 85;
967 y = av_clip_uint8((RY * r + GY * g + BY * b + ( 33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
968 u = av_clip_uint8((RU * r + GU * g + BU * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
969 v = av_clip_uint8((RV * r + GV * g + BV * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
970 c->pal_yuv[i]= y + (u<<8) + (v<<16) + (a<<24);
972 switch (c->dstFormat) {
977 c->pal_rgb[i]= r + (g<<8) + (b<<16) + (a<<24);
979 case PIX_FMT_BGR32_1:
983 c->pal_rgb[i]= a + (r<<8) + (g<<16) + (b<<24);
985 case PIX_FMT_RGB32_1:
989 c->pal_rgb[i]= a + (b<<8) + (g<<16) + (r<<24);
996 c->pal_rgb[i]= b + (g<<8) + (r<<16) + (a<<24);
1001 if (c->src0Alpha && !c->dst0Alpha && isALPHA(c->dstFormat)) {
1004 rgb0_tmp = av_malloc(FFABS(srcStride[0]) * srcSliceH + 32);
1005 base = srcStride[0] < 0 ? rgb0_tmp - srcStride[0] * (srcSliceH-1) : rgb0_tmp;
1006 for (y=0; y<srcSliceH; y++){
1007 memcpy(base + srcStride[0]*y, src2[0] + srcStride[0]*y, 4*c->srcW);
1008 for (x=c->src0Alpha-1; x<4*c->srcW; x+=4) {
1009 base[ srcStride[0]*y + x] = 0xFF;
1015 // copy strides, so they can safely be modified
1016 if (c->sliceDir == 1) {
1017 // slices go from top to bottom
1018 int srcStride2[4] = { srcStride[0], srcStride[1], srcStride[2],
1020 int dstStride2[4] = { dstStride[0], dstStride[1], dstStride[2],
1023 reset_ptr(src2, c->srcFormat);
1024 reset_ptr((void*)dst2, c->dstFormat);
1026 /* reset slice direction at end of frame */
1027 if (srcSliceY + srcSliceH == c->srcH)
1030 ret = c->swScale(c, src2, srcStride2, srcSliceY, srcSliceH, dst2,
1033 // slices go from bottom to top => we flip the image internally
1034 int srcStride2[4] = { -srcStride[0], -srcStride[1], -srcStride[2],
1036 int dstStride2[4] = { -dstStride[0], -dstStride[1], -dstStride[2],
1039 src2[0] += (srcSliceH - 1) * srcStride[0];
1040 if (!usePal(c->srcFormat))
1041 src2[1] += ((srcSliceH >> c->chrSrcVSubSample) - 1) * srcStride[1];
1042 src2[2] += ((srcSliceH >> c->chrSrcVSubSample) - 1) * srcStride[2];
1043 src2[3] += (srcSliceH - 1) * srcStride[3];
1044 dst2[0] += ( c->dstH - 1) * dstStride[0];
1045 dst2[1] += ((c->dstH >> c->chrDstVSubSample) - 1) * dstStride[1];
1046 dst2[2] += ((c->dstH >> c->chrDstVSubSample) - 1) * dstStride[2];
1047 dst2[3] += ( c->dstH - 1) * dstStride[3];
1049 reset_ptr(src2, c->srcFormat);
1050 reset_ptr((void*)dst2, c->dstFormat);
1052 /* reset slice direction at end of frame */
1056 ret = c->swScale(c, src2, srcStride2, c->srcH-srcSliceY-srcSliceH,
1057 srcSliceH, dst2, dstStride2);
1064 /* Convert the palette to the same packed 32-bit format as the palette */
1065 void sws_convertPalette8ToPacked32(const uint8_t *src, uint8_t *dst,
1066 int num_pixels, const uint8_t *palette)
1070 for (i = 0; i < num_pixels; i++)
1071 ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i]];
1074 /* Palette format: ABCD -> dst format: ABC */
1075 void sws_convertPalette8ToPacked24(const uint8_t *src, uint8_t *dst,
1076 int num_pixels, const uint8_t *palette)
1080 for (i = 0; i < num_pixels; i++) {
1082 dst[0] = palette[src[i] * 4 + 0];
1083 dst[1] = palette[src[i] * 4 + 1];
1084 dst[2] = palette[src[i] * 4 + 2];