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
26 #include "libavutil/avassert.h"
27 #include "libavutil/avutil.h"
28 #include "libavutil/bswap.h"
29 #include "libavutil/cpu.h"
30 #include "libavutil/imgutils.h"
31 #include "libavutil/intreadwrite.h"
32 #include "libavutil/mathematics.h"
33 #include "libavutil/pixdesc.h"
36 #include "swscale_internal.h"
39 DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_128
)[9][8] = {
40 { 36, 68, 60, 92, 34, 66, 58, 90, },
41 { 100, 4, 124, 28, 98, 2, 122, 26, },
42 { 52, 84, 44, 76, 50, 82, 42, 74, },
43 { 116, 20, 108, 12, 114, 18, 106, 10, },
44 { 32, 64, 56, 88, 38, 70, 62, 94, },
45 { 96, 0, 120, 24, 102, 6, 126, 30, },
46 { 48, 80, 40, 72, 54, 86, 46, 78, },
47 { 112, 16, 104, 8, 118, 22, 110, 14, },
48 { 36, 68, 60, 92, 34, 66, 58, 90, },
51 DECLARE_ALIGNED(8, static const uint8_t, sws_pb_64
)[8] = {
52 64, 64, 64, 64, 64, 64, 64, 64
55 static av_always_inline
void fillPlane(uint8_t *plane
, int stride
, int width
,
56 int height
, int y
, uint8_t val
)
59 uint8_t *ptr
= plane
+ stride
* y
;
60 for (i
= 0; i
< height
; i
++) {
61 memset(ptr
, val
, width
);
66 static void hScale16To19_c(SwsContext
*c
, int16_t *_dst
, int dstW
,
67 const uint8_t *_src
, const int16_t *filter
,
68 const int32_t *filterPos
, int filterSize
)
70 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(c
->srcFormat
);
72 int32_t *dst
= (int32_t *) _dst
;
73 const uint16_t *src
= (const uint16_t *) _src
;
74 int bits
= desc
->comp
[0].depth_minus1
;
77 if((isAnyRGB(c
->srcFormat
) || c
->srcFormat
==AV_PIX_FMT_PAL8
) && desc
->comp
[0].depth_minus1
<15)
80 for (i
= 0; i
< dstW
; i
++) {
82 int srcPos
= filterPos
[i
];
85 for (j
= 0; j
< filterSize
; j
++) {
86 val
+= src
[srcPos
+ j
] * filter
[filterSize
* i
+ j
];
88 // filter=14 bit, input=16 bit, output=30 bit, >> 11 makes 19 bit
89 dst
[i
] = FFMIN(val
>> sh
, (1 << 19) - 1);
93 static void hScale16To15_c(SwsContext
*c
, int16_t *dst
, int dstW
,
94 const uint8_t *_src
, const int16_t *filter
,
95 const int32_t *filterPos
, int filterSize
)
97 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(c
->srcFormat
);
99 const uint16_t *src
= (const uint16_t *) _src
;
100 int sh
= desc
->comp
[0].depth_minus1
;
103 sh
= isAnyRGB(c
->srcFormat
) || c
->srcFormat
==AV_PIX_FMT_PAL8
? 13 : desc
->comp
[0].depth_minus1
;
105 for (i
= 0; i
< dstW
; i
++) {
107 int srcPos
= filterPos
[i
];
110 for (j
= 0; j
< filterSize
; j
++) {
111 val
+= src
[srcPos
+ j
] * filter
[filterSize
* i
+ j
];
113 // filter=14 bit, input=16 bit, output=30 bit, >> 15 makes 15 bit
114 dst
[i
] = FFMIN(val
>> sh
, (1 << 15) - 1);
118 // bilinear / bicubic scaling
119 static void hScale8To15_c(SwsContext
*c
, int16_t *dst
, int dstW
,
120 const uint8_t *src
, const int16_t *filter
,
121 const int32_t *filterPos
, int filterSize
)
124 for (i
= 0; i
< dstW
; i
++) {
126 int srcPos
= filterPos
[i
];
128 for (j
= 0; j
< filterSize
; j
++) {
129 val
+= ((int)src
[srcPos
+ j
]) * filter
[filterSize
* i
+ j
];
131 dst
[i
] = FFMIN(val
>> 7, (1 << 15) - 1); // the cubic equation does overflow ...
135 static void hScale8To19_c(SwsContext
*c
, int16_t *_dst
, int dstW
,
136 const uint8_t *src
, const int16_t *filter
,
137 const int32_t *filterPos
, int filterSize
)
140 int32_t *dst
= (int32_t *) _dst
;
141 for (i
= 0; i
< dstW
; i
++) {
143 int srcPos
= filterPos
[i
];
145 for (j
= 0; j
< filterSize
; j
++) {
146 val
+= ((int)src
[srcPos
+ j
]) * filter
[filterSize
* i
+ j
];
148 dst
[i
] = FFMIN(val
>> 3, (1 << 19) - 1); // the cubic equation does overflow ...
152 // FIXME all pal and rgb srcFormats could do this conversion as well
153 // FIXME all scalers more complex than bilinear could do half of this transform
154 static void chrRangeToJpeg_c(int16_t *dstU
, int16_t *dstV
, int width
)
157 for (i
= 0; i
< width
; i
++) {
158 dstU
[i
] = (FFMIN(dstU
[i
], 30775) * 4663 - 9289992) >> 12; // -264
159 dstV
[i
] = (FFMIN(dstV
[i
], 30775) * 4663 - 9289992) >> 12; // -264
163 static void chrRangeFromJpeg_c(int16_t *dstU
, int16_t *dstV
, int width
)
166 for (i
= 0; i
< width
; i
++) {
167 dstU
[i
] = (dstU
[i
] * 1799 + 4081085) >> 11; // 1469
168 dstV
[i
] = (dstV
[i
] * 1799 + 4081085) >> 11; // 1469
172 static void lumRangeToJpeg_c(int16_t *dst
, int width
)
175 for (i
= 0; i
< width
; i
++)
176 dst
[i
] = (FFMIN(dst
[i
], 30189) * 19077 - 39057361) >> 14;
179 static void lumRangeFromJpeg_c(int16_t *dst
, int width
)
182 for (i
= 0; i
< width
; i
++)
183 dst
[i
] = (dst
[i
] * 14071 + 33561947) >> 14;
186 static void chrRangeToJpeg16_c(int16_t *_dstU
, int16_t *_dstV
, int width
)
189 int32_t *dstU
= (int32_t *) _dstU
;
190 int32_t *dstV
= (int32_t *) _dstV
;
191 for (i
= 0; i
< width
; i
++) {
192 dstU
[i
] = (FFMIN(dstU
[i
], 30775 << 4) * 4663 - (9289992 << 4)) >> 12; // -264
193 dstV
[i
] = (FFMIN(dstV
[i
], 30775 << 4) * 4663 - (9289992 << 4)) >> 12; // -264
197 static void chrRangeFromJpeg16_c(int16_t *_dstU
, int16_t *_dstV
, int width
)
200 int32_t *dstU
= (int32_t *) _dstU
;
201 int32_t *dstV
= (int32_t *) _dstV
;
202 for (i
= 0; i
< width
; i
++) {
203 dstU
[i
] = (dstU
[i
] * 1799 + (4081085 << 4)) >> 11; // 1469
204 dstV
[i
] = (dstV
[i
] * 1799 + (4081085 << 4)) >> 11; // 1469
208 static void lumRangeToJpeg16_c(int16_t *_dst
, int width
)
211 int32_t *dst
= (int32_t *) _dst
;
212 for (i
= 0; i
< width
; i
++) {
213 dst
[i
] = ((int)(FFMIN(dst
[i
], 30189 << 4) * 4769U - (39057361 << 2))) >> 12;
217 static void lumRangeFromJpeg16_c(int16_t *_dst
, int width
)
220 int32_t *dst
= (int32_t *) _dst
;
221 for (i
= 0; i
< width
; i
++)
222 dst
[i
] = (dst
[i
]*(14071/4) + (33561947<<4)/4)>>12;
225 // *** horizontal scale Y line to temp buffer
226 static av_always_inline
void hyscale(SwsContext
*c
, int16_t *dst
, int dstWidth
,
227 const uint8_t *src_in
[4],
229 const int16_t *hLumFilter
,
230 const int32_t *hLumFilterPos
,
232 uint8_t *formatConvBuffer
,
233 uint32_t *pal
, int isAlpha
)
235 void (*toYV12
)(uint8_t *, const uint8_t *, const uint8_t *, const uint8_t *, int, uint32_t *) =
236 isAlpha
? c
->alpToYV12
: c
->lumToYV12
;
237 void (*convertRange
)(int16_t *, int) = isAlpha
? NULL
: c
->lumConvertRange
;
238 const uint8_t *src
= src_in
[isAlpha
? 3 : 0];
241 toYV12(formatConvBuffer
, src
, src_in
[1], src_in
[2], srcW
, pal
);
242 src
= formatConvBuffer
;
243 } else if (c
->readLumPlanar
&& !isAlpha
) {
244 c
->readLumPlanar(formatConvBuffer
, src_in
, srcW
, c
->input_rgb2yuv_table
);
245 src
= formatConvBuffer
;
246 } else if (c
->readAlpPlanar
&& isAlpha
) {
247 c
->readAlpPlanar(formatConvBuffer
, src_in
, srcW
, NULL
);
248 src
= formatConvBuffer
;
251 if (!c
->hyscale_fast
) {
252 c
->hyScale(c
, dst
, dstWidth
, src
, hLumFilter
,
253 hLumFilterPos
, hLumFilterSize
);
254 } else { // fast bilinear upscale / crap downscale
255 c
->hyscale_fast(c
, dst
, dstWidth
, src
, srcW
, xInc
);
259 convertRange(dst
, dstWidth
);
262 static av_always_inline
void hcscale(SwsContext
*c
, int16_t *dst1
,
263 int16_t *dst2
, int dstWidth
,
264 const uint8_t *src_in
[4],
266 const int16_t *hChrFilter
,
267 const int32_t *hChrFilterPos
,
269 uint8_t *formatConvBuffer
, uint32_t *pal
)
271 const uint8_t *src1
= src_in
[1], *src2
= src_in
[2];
273 uint8_t *buf2
= formatConvBuffer
+
274 FFALIGN(srcW
*2+78, 16);
275 c
->chrToYV12(formatConvBuffer
, buf2
, src_in
[0], src1
, src2
, srcW
, pal
);
276 src1
= formatConvBuffer
;
278 } else if (c
->readChrPlanar
) {
279 uint8_t *buf2
= formatConvBuffer
+
280 FFALIGN(srcW
*2+78, 16);
281 c
->readChrPlanar(formatConvBuffer
, buf2
, src_in
, srcW
, c
->input_rgb2yuv_table
);
282 src1
= formatConvBuffer
;
286 if (!c
->hcscale_fast
) {
287 c
->hcScale(c
, dst1
, dstWidth
, src1
, hChrFilter
, hChrFilterPos
, hChrFilterSize
);
288 c
->hcScale(c
, dst2
, dstWidth
, src2
, hChrFilter
, hChrFilterPos
, hChrFilterSize
);
289 } else { // fast bilinear upscale / crap downscale
290 c
->hcscale_fast(c
, dst1
, dst2
, dstWidth
, src1
, src2
, srcW
, xInc
);
293 if (c
->chrConvertRange
)
294 c
->chrConvertRange(dst1
, dst2
, dstWidth
);
297 #define DEBUG_SWSCALE_BUFFERS 0
298 #define DEBUG_BUFFERS(...) \
299 if (DEBUG_SWSCALE_BUFFERS) \
300 av_log(c, AV_LOG_DEBUG, __VA_ARGS__)
302 static int swscale(SwsContext
*c
, const uint8_t *src
[],
303 int srcStride
[], int srcSliceY
,
304 int srcSliceH
, uint8_t *dst
[], int dstStride
[])
306 /* load a few things into local vars to make the code more readable?
308 const int srcW
= c
->srcW
;
309 const int dstW
= c
->dstW
;
310 const int dstH
= c
->dstH
;
311 const int chrDstW
= c
->chrDstW
;
312 const int chrSrcW
= c
->chrSrcW
;
313 const int lumXInc
= c
->lumXInc
;
314 const int chrXInc
= c
->chrXInc
;
315 const enum AVPixelFormat dstFormat
= c
->dstFormat
;
316 const int flags
= c
->flags
;
317 int32_t *vLumFilterPos
= c
->vLumFilterPos
;
318 int32_t *vChrFilterPos
= c
->vChrFilterPos
;
319 int32_t *hLumFilterPos
= c
->hLumFilterPos
;
320 int32_t *hChrFilterPos
= c
->hChrFilterPos
;
321 int16_t *hLumFilter
= c
->hLumFilter
;
322 int16_t *hChrFilter
= c
->hChrFilter
;
323 int32_t *lumMmxFilter
= c
->lumMmxFilter
;
324 int32_t *chrMmxFilter
= c
->chrMmxFilter
;
325 const int vLumFilterSize
= c
->vLumFilterSize
;
326 const int vChrFilterSize
= c
->vChrFilterSize
;
327 const int hLumFilterSize
= c
->hLumFilterSize
;
328 const int hChrFilterSize
= c
->hChrFilterSize
;
329 int16_t **lumPixBuf
= c
->lumPixBuf
;
330 int16_t **chrUPixBuf
= c
->chrUPixBuf
;
331 int16_t **chrVPixBuf
= c
->chrVPixBuf
;
332 int16_t **alpPixBuf
= c
->alpPixBuf
;
333 const int vLumBufSize
= c
->vLumBufSize
;
334 const int vChrBufSize
= c
->vChrBufSize
;
335 uint8_t *formatConvBuffer
= c
->formatConvBuffer
;
336 uint32_t *pal
= c
->pal_yuv
;
337 yuv2planar1_fn yuv2plane1
= c
->yuv2plane1
;
338 yuv2planarX_fn yuv2planeX
= c
->yuv2planeX
;
339 yuv2interleavedX_fn yuv2nv12cX
= c
->yuv2nv12cX
;
340 yuv2packed1_fn yuv2packed1
= c
->yuv2packed1
;
341 yuv2packed2_fn yuv2packed2
= c
->yuv2packed2
;
342 yuv2packedX_fn yuv2packedX
= c
->yuv2packedX
;
343 yuv2anyX_fn yuv2anyX
= c
->yuv2anyX
;
344 const int chrSrcSliceY
= srcSliceY
>> c
->chrSrcVSubSample
;
345 const int chrSrcSliceH
= FF_CEIL_RSHIFT(srcSliceH
, c
->chrSrcVSubSample
);
346 int should_dither
= is9_OR_10BPS(c
->srcFormat
) ||
347 is16BPS(c
->srcFormat
);
350 /* vars which will change and which we need to store back in the context */
352 int lumBufIndex
= c
->lumBufIndex
;
353 int chrBufIndex
= c
->chrBufIndex
;
354 int lastInLumBuf
= c
->lastInLumBuf
;
355 int lastInChrBuf
= c
->lastInChrBuf
;
357 if (!usePal(c
->srcFormat
)) {
358 pal
= c
->input_rgb2yuv_table
;
361 if (isPacked(c
->srcFormat
)) {
369 srcStride
[3] = srcStride
[0];
371 srcStride
[1] <<= c
->vChrDrop
;
372 srcStride
[2] <<= c
->vChrDrop
;
374 DEBUG_BUFFERS("swscale() %p[%d] %p[%d] %p[%d] %p[%d] -> %p[%d] %p[%d] %p[%d] %p[%d]\n",
375 src
[0], srcStride
[0], src
[1], srcStride
[1],
376 src
[2], srcStride
[2], src
[3], srcStride
[3],
377 dst
[0], dstStride
[0], dst
[1], dstStride
[1],
378 dst
[2], dstStride
[2], dst
[3], dstStride
[3]);
379 DEBUG_BUFFERS("srcSliceY: %d srcSliceH: %d dstY: %d dstH: %d\n",
380 srcSliceY
, srcSliceH
, dstY
, dstH
);
381 DEBUG_BUFFERS("vLumFilterSize: %d vLumBufSize: %d vChrFilterSize: %d vChrBufSize: %d\n",
382 vLumFilterSize
, vLumBufSize
, vChrFilterSize
, vChrBufSize
);
384 if (dstStride
[0]&15 || dstStride
[1]&15 ||
385 dstStride
[2]&15 || dstStride
[3]&15) {
386 static int warnedAlready
= 0; // FIXME maybe move this into the context
387 if (flags
& SWS_PRINT_INFO
&& !warnedAlready
) {
388 av_log(c
, AV_LOG_WARNING
,
389 "Warning: dstStride is not aligned!\n"
390 " ->cannot do aligned memory accesses anymore\n");
395 if ( (uintptr_t)dst
[0]&15 || (uintptr_t)dst
[1]&15 || (uintptr_t)dst
[2]&15
396 || (uintptr_t)src
[0]&15 || (uintptr_t)src
[1]&15 || (uintptr_t)src
[2]&15
397 || dstStride
[0]&15 || dstStride
[1]&15 || dstStride
[2]&15 || dstStride
[3]&15
398 || srcStride
[0]&15 || srcStride
[1]&15 || srcStride
[2]&15 || srcStride
[3]&15
400 static int warnedAlready
=0;
401 int cpu_flags
= av_get_cpu_flags();
402 if (HAVE_MMXEXT
&& (cpu_flags
& AV_CPU_FLAG_SSE2
) && !warnedAlready
){
403 av_log(c
, AV_LOG_WARNING
, "Warning: data is not aligned! This can lead to a speedloss\n");
408 /* Note the user might start scaling the picture in the middle so this
409 * will not get executed. This is not really intended but works
410 * currently, so people might do it. */
411 if (srcSliceY
== 0) {
419 if (!should_dither
) {
420 c
->chrDither8
= c
->lumDither8
= sws_pb_64
;
424 for (; dstY
< dstH
; dstY
++) {
425 const int chrDstY
= dstY
>> c
->chrDstVSubSample
;
427 dst
[0] + dstStride
[0] * dstY
,
428 dst
[1] + dstStride
[1] * chrDstY
,
429 dst
[2] + dstStride
[2] * chrDstY
,
430 (CONFIG_SWSCALE_ALPHA
&& alpPixBuf
) ? dst
[3] + dstStride
[3] * dstY
: NULL
,
432 int use_mmx_vfilter
= c
->use_mmx_vfilter
;
434 // First line needed as input
435 const int firstLumSrcY
= FFMAX(1 - vLumFilterSize
, vLumFilterPos
[dstY
]);
436 const int firstLumSrcY2
= FFMAX(1 - vLumFilterSize
, vLumFilterPos
[FFMIN(dstY
| ((1 << c
->chrDstVSubSample
) - 1), dstH
- 1)]);
437 // First line needed as input
438 const int firstChrSrcY
= FFMAX(1 - vChrFilterSize
, vChrFilterPos
[chrDstY
]);
440 // Last line needed as input
441 int lastLumSrcY
= FFMIN(c
->srcH
, firstLumSrcY
+ vLumFilterSize
) - 1;
442 int lastLumSrcY2
= FFMIN(c
->srcH
, firstLumSrcY2
+ vLumFilterSize
) - 1;
443 int lastChrSrcY
= FFMIN(c
->chrSrcH
, firstChrSrcY
+ vChrFilterSize
) - 1;
446 // handle holes (FAST_BILINEAR & weird filters)
447 if (firstLumSrcY
> lastInLumBuf
)
448 lastInLumBuf
= firstLumSrcY
- 1;
449 if (firstChrSrcY
> lastInChrBuf
)
450 lastInChrBuf
= firstChrSrcY
- 1;
451 av_assert0(firstLumSrcY
>= lastInLumBuf
- vLumBufSize
+ 1);
452 av_assert0(firstChrSrcY
>= lastInChrBuf
- vChrBufSize
+ 1);
454 DEBUG_BUFFERS("dstY: %d\n", dstY
);
455 DEBUG_BUFFERS("\tfirstLumSrcY: %d lastLumSrcY: %d lastInLumBuf: %d\n",
456 firstLumSrcY
, lastLumSrcY
, lastInLumBuf
);
457 DEBUG_BUFFERS("\tfirstChrSrcY: %d lastChrSrcY: %d lastInChrBuf: %d\n",
458 firstChrSrcY
, lastChrSrcY
, lastInChrBuf
);
460 // Do we have enough lines in this slice to output the dstY line
461 enough_lines
= lastLumSrcY2
< srcSliceY
+ srcSliceH
&&
462 lastChrSrcY
< FF_CEIL_RSHIFT(srcSliceY
+ srcSliceH
, c
->chrSrcVSubSample
);
465 lastLumSrcY
= srcSliceY
+ srcSliceH
- 1;
466 lastChrSrcY
= chrSrcSliceY
+ chrSrcSliceH
- 1;
467 DEBUG_BUFFERS("buffering slice: lastLumSrcY %d lastChrSrcY %d\n",
468 lastLumSrcY
, lastChrSrcY
);
471 // Do horizontal scaling
472 while (lastInLumBuf
< lastLumSrcY
) {
473 const uint8_t *src1
[4] = {
474 src
[0] + (lastInLumBuf
+ 1 - srcSliceY
) * srcStride
[0],
475 src
[1] + (lastInLumBuf
+ 1 - srcSliceY
) * srcStride
[1],
476 src
[2] + (lastInLumBuf
+ 1 - srcSliceY
) * srcStride
[2],
477 src
[3] + (lastInLumBuf
+ 1 - srcSliceY
) * srcStride
[3],
480 av_assert0(lumBufIndex
< 2 * vLumBufSize
);
481 av_assert0(lastInLumBuf
+ 1 - srcSliceY
< srcSliceH
);
482 av_assert0(lastInLumBuf
+ 1 - srcSliceY
>= 0);
483 hyscale(c
, lumPixBuf
[lumBufIndex
], dstW
, src1
, srcW
, lumXInc
,
484 hLumFilter
, hLumFilterPos
, hLumFilterSize
,
485 formatConvBuffer
, pal
, 0);
486 if (CONFIG_SWSCALE_ALPHA
&& alpPixBuf
)
487 hyscale(c
, alpPixBuf
[lumBufIndex
], dstW
, src1
, srcW
,
488 lumXInc
, hLumFilter
, hLumFilterPos
, hLumFilterSize
,
489 formatConvBuffer
, pal
, 1);
491 DEBUG_BUFFERS("\t\tlumBufIndex %d: lastInLumBuf: %d\n",
492 lumBufIndex
, lastInLumBuf
);
494 while (lastInChrBuf
< lastChrSrcY
) {
495 const uint8_t *src1
[4] = {
496 src
[0] + (lastInChrBuf
+ 1 - chrSrcSliceY
) * srcStride
[0],
497 src
[1] + (lastInChrBuf
+ 1 - chrSrcSliceY
) * srcStride
[1],
498 src
[2] + (lastInChrBuf
+ 1 - chrSrcSliceY
) * srcStride
[2],
499 src
[3] + (lastInChrBuf
+ 1 - chrSrcSliceY
) * srcStride
[3],
502 av_assert0(chrBufIndex
< 2 * vChrBufSize
);
503 av_assert0(lastInChrBuf
+ 1 - chrSrcSliceY
< (chrSrcSliceH
));
504 av_assert0(lastInChrBuf
+ 1 - chrSrcSliceY
>= 0);
505 // FIXME replace parameters through context struct (some at least)
507 if (c
->needs_hcscale
)
508 hcscale(c
, chrUPixBuf
[chrBufIndex
], chrVPixBuf
[chrBufIndex
],
509 chrDstW
, src1
, chrSrcW
, chrXInc
,
510 hChrFilter
, hChrFilterPos
, hChrFilterSize
,
511 formatConvBuffer
, pal
);
513 DEBUG_BUFFERS("\t\tchrBufIndex %d: lastInChrBuf: %d\n",
514 chrBufIndex
, lastInChrBuf
);
516 // wrap buf index around to stay inside the ring buffer
517 if (lumBufIndex
>= vLumBufSize
)
518 lumBufIndex
-= vLumBufSize
;
519 if (chrBufIndex
>= vChrBufSize
)
520 chrBufIndex
-= vChrBufSize
;
522 break; // we can't output a dstY line so let's try with the next slice
525 updateMMXDitherTables(c
, dstY
, lumBufIndex
, chrBufIndex
,
526 lastInLumBuf
, lastInChrBuf
);
529 c
->chrDither8
= ff_dither_8x8_128
[chrDstY
& 7];
530 c
->lumDither8
= ff_dither_8x8_128
[dstY
& 7];
532 if (dstY
>= dstH
- 2) {
533 /* hmm looks like we can't use MMX here without overwriting
534 * this array's tail */
535 ff_sws_init_output_funcs(c
, &yuv2plane1
, &yuv2planeX
, &yuv2nv12cX
,
536 &yuv2packed1
, &yuv2packed2
, &yuv2packedX
, &yuv2anyX
);
541 const int16_t **lumSrcPtr
= (const int16_t **)(void*) lumPixBuf
+ lumBufIndex
+ firstLumSrcY
- lastInLumBuf
+ vLumBufSize
;
542 const int16_t **chrUSrcPtr
= (const int16_t **)(void*) chrUPixBuf
+ chrBufIndex
+ firstChrSrcY
- lastInChrBuf
+ vChrBufSize
;
543 const int16_t **chrVSrcPtr
= (const int16_t **)(void*) chrVPixBuf
+ chrBufIndex
+ firstChrSrcY
- lastInChrBuf
+ vChrBufSize
;
544 const int16_t **alpSrcPtr
= (CONFIG_SWSCALE_ALPHA
&& alpPixBuf
) ?
545 (const int16_t **)(void*) alpPixBuf
+ lumBufIndex
+ firstLumSrcY
- lastInLumBuf
+ vLumBufSize
: NULL
;
546 int16_t *vLumFilter
= c
->vLumFilter
;
547 int16_t *vChrFilter
= c
->vChrFilter
;
549 if (isPlanarYUV(dstFormat
) ||
550 (isGray(dstFormat
) && !isALPHA(dstFormat
))) { // YV12 like
551 const int chrSkipMask
= (1 << c
->chrDstVSubSample
) - 1;
553 vLumFilter
+= dstY
* vLumFilterSize
;
554 vChrFilter
+= chrDstY
* vChrFilterSize
;
556 // av_assert0(use_mmx_vfilter != (
557 // yuv2planeX == yuv2planeX_10BE_c
558 // || yuv2planeX == yuv2planeX_10LE_c
559 // || yuv2planeX == yuv2planeX_9BE_c
560 // || yuv2planeX == yuv2planeX_9LE_c
561 // || yuv2planeX == yuv2planeX_16BE_c
562 // || yuv2planeX == yuv2planeX_16LE_c
563 // || yuv2planeX == yuv2planeX_8_c) || !ARCH_X86);
566 vLumFilter
= (int16_t *)c
->lumMmxFilter
;
567 vChrFilter
= (int16_t *)c
->chrMmxFilter
;
570 if (vLumFilterSize
== 1) {
571 yuv2plane1(lumSrcPtr
[0], dest
[0], dstW
, c
->lumDither8
, 0);
573 yuv2planeX(vLumFilter
, vLumFilterSize
,
575 dstW
, c
->lumDither8
, 0);
578 if (!((dstY
& chrSkipMask
) || isGray(dstFormat
))) {
580 yuv2nv12cX(c
, vChrFilter
,
581 vChrFilterSize
, chrUSrcPtr
, chrVSrcPtr
,
583 } else if (vChrFilterSize
== 1) {
584 yuv2plane1(chrUSrcPtr
[0], dest
[1], chrDstW
, c
->chrDither8
, 0);
585 yuv2plane1(chrVSrcPtr
[0], dest
[2], chrDstW
, c
->chrDither8
, 3);
587 yuv2planeX(vChrFilter
,
588 vChrFilterSize
, chrUSrcPtr
, dest
[1],
589 chrDstW
, c
->chrDither8
, 0);
590 yuv2planeX(vChrFilter
,
591 vChrFilterSize
, chrVSrcPtr
, dest
[2],
592 chrDstW
, c
->chrDither8
, use_mmx_vfilter
? (c
->uv_offx2
>> 1) : 3);
596 if (CONFIG_SWSCALE_ALPHA
&& alpPixBuf
) {
598 vLumFilter
= (int16_t *)c
->alpMmxFilter
;
600 if (vLumFilterSize
== 1) {
601 yuv2plane1(alpSrcPtr
[0], dest
[3], dstW
,
604 yuv2planeX(vLumFilter
,
605 vLumFilterSize
, alpSrcPtr
, dest
[3],
606 dstW
, c
->lumDither8
, 0);
609 } else if (yuv2packedX
) {
610 av_assert1(lumSrcPtr
+ vLumFilterSize
- 1 < (const int16_t **)lumPixBuf
+ vLumBufSize
* 2);
611 av_assert1(chrUSrcPtr
+ vChrFilterSize
- 1 < (const int16_t **)chrUPixBuf
+ vChrBufSize
* 2);
612 if (c
->yuv2packed1
&& vLumFilterSize
== 1 &&
613 vChrFilterSize
<= 2) { // unscaled RGB
614 int chrAlpha
= vChrFilterSize
== 1 ? 0 : vChrFilter
[2 * dstY
+ 1];
615 yuv2packed1(c
, *lumSrcPtr
, chrUSrcPtr
, chrVSrcPtr
,
616 alpPixBuf
? *alpSrcPtr
: NULL
,
617 dest
[0], dstW
, chrAlpha
, dstY
);
618 } else if (c
->yuv2packed2
&& vLumFilterSize
== 2 &&
619 vChrFilterSize
== 2) { // bilinear upscale RGB
620 int lumAlpha
= vLumFilter
[2 * dstY
+ 1];
621 int chrAlpha
= vChrFilter
[2 * dstY
+ 1];
623 lumMmxFilter
[3] = vLumFilter
[2 * dstY
] * 0x10001;
625 chrMmxFilter
[3] = vChrFilter
[2 * chrDstY
] * 0x10001;
626 yuv2packed2(c
, lumSrcPtr
, chrUSrcPtr
, chrVSrcPtr
,
627 alpPixBuf
? alpSrcPtr
: NULL
,
628 dest
[0], dstW
, lumAlpha
, chrAlpha
, dstY
);
629 } else { // general RGB
630 yuv2packedX(c
, vLumFilter
+ dstY
* vLumFilterSize
,
631 lumSrcPtr
, vLumFilterSize
,
632 vChrFilter
+ dstY
* vChrFilterSize
,
633 chrUSrcPtr
, chrVSrcPtr
, vChrFilterSize
,
634 alpSrcPtr
, dest
[0], dstW
, dstY
);
637 av_assert1(!yuv2packed1
&& !yuv2packed2
);
638 yuv2anyX(c
, vLumFilter
+ dstY
* vLumFilterSize
,
639 lumSrcPtr
, vLumFilterSize
,
640 vChrFilter
+ dstY
* vChrFilterSize
,
641 chrUSrcPtr
, chrVSrcPtr
, vChrFilterSize
,
642 alpSrcPtr
, dest
, dstW
, dstY
);
646 if (isPlanar(dstFormat
) && isALPHA(dstFormat
) && !alpPixBuf
) {
648 int height
= dstY
- lastDstY
;
650 if (is16BPS(dstFormat
) || isNBPS(dstFormat
)) {
651 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(dstFormat
);
652 fillPlane16(dst
[3], dstStride
[3], length
, height
, lastDstY
,
653 1, desc
->comp
[3].depth_minus1
,
656 fillPlane(dst
[3], dstStride
[3], length
, height
, lastDstY
, 255);
659 #if HAVE_MMXEXT_INLINE
660 if (av_get_cpu_flags() & AV_CPU_FLAG_MMXEXT
)
661 __asm__
volatile ("sfence" ::: "memory");
665 /* store changed local vars back in the context */
667 c
->lumBufIndex
= lumBufIndex
;
668 c
->chrBufIndex
= chrBufIndex
;
669 c
->lastInLumBuf
= lastInLumBuf
;
670 c
->lastInChrBuf
= lastInChrBuf
;
672 return dstY
- lastDstY
;
675 av_cold
void ff_sws_init_range_convert(SwsContext
*c
)
677 c
->lumConvertRange
= NULL
;
678 c
->chrConvertRange
= NULL
;
679 if (c
->srcRange
!= c
->dstRange
&& !isAnyRGB(c
->dstFormat
)) {
680 if (c
->dstBpc
<= 14) {
682 c
->lumConvertRange
= lumRangeFromJpeg_c
;
683 c
->chrConvertRange
= chrRangeFromJpeg_c
;
685 c
->lumConvertRange
= lumRangeToJpeg_c
;
686 c
->chrConvertRange
= chrRangeToJpeg_c
;
690 c
->lumConvertRange
= lumRangeFromJpeg16_c
;
691 c
->chrConvertRange
= chrRangeFromJpeg16_c
;
693 c
->lumConvertRange
= lumRangeToJpeg16_c
;
694 c
->chrConvertRange
= chrRangeToJpeg16_c
;
700 static av_cold
void sws_init_swscale(SwsContext
*c
)
702 enum AVPixelFormat srcFormat
= c
->srcFormat
;
704 ff_sws_init_output_funcs(c
, &c
->yuv2plane1
, &c
->yuv2planeX
,
705 &c
->yuv2nv12cX
, &c
->yuv2packed1
,
706 &c
->yuv2packed2
, &c
->yuv2packedX
, &c
->yuv2anyX
);
708 ff_sws_init_input_funcs(c
);
711 if (c
->srcBpc
== 8) {
712 if (c
->dstBpc
<= 14) {
713 c
->hyScale
= c
->hcScale
= hScale8To15_c
;
714 if (c
->flags
& SWS_FAST_BILINEAR
) {
715 c
->hyscale_fast
= ff_hyscale_fast_c
;
716 c
->hcscale_fast
= ff_hcscale_fast_c
;
719 c
->hyScale
= c
->hcScale
= hScale8To19_c
;
722 c
->hyScale
= c
->hcScale
= c
->dstBpc
> 14 ? hScale16To19_c
726 ff_sws_init_range_convert(c
);
728 if (!(isGray(srcFormat
) || isGray(c
->dstFormat
) ||
729 srcFormat
== AV_PIX_FMT_MONOBLACK
|| srcFormat
== AV_PIX_FMT_MONOWHITE
))
730 c
->needs_hcscale
= 1;
733 SwsFunc
ff_getSwsFunc(SwsContext
*c
)
738 ff_sws_init_swscale_ppc(c
);
740 ff_sws_init_swscale_x86(c
);
745 static void reset_ptr(const uint8_t *src
[], int format
)
747 if (!isALPHA(format
))
749 if (!isPlanar(format
)) {
750 src
[3] = src
[2] = NULL
;
757 static int check_image_pointers(const uint8_t * const data
[4], enum AVPixelFormat pix_fmt
,
758 const int linesizes
[4])
760 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(pix_fmt
);
763 for (i
= 0; i
< 4; i
++) {
764 int plane
= desc
->comp
[i
].plane
;
765 if (!data
[plane
] || !linesizes
[plane
])
772 static void xyz12Torgb48(struct SwsContext
*c
, uint16_t *dst
,
773 const uint16_t *src
, int stride
, int h
)
776 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(c
->srcFormat
);
778 for (yp
=0; yp
<h
; yp
++) {
779 for (xp
=0; xp
+2<stride
; xp
+=3) {
780 int x
, y
, z
, r
, g
, b
;
782 if (desc
->flags
& AV_PIX_FMT_FLAG_BE
) {
783 x
= AV_RB16(src
+ xp
+ 0);
784 y
= AV_RB16(src
+ xp
+ 1);
785 z
= AV_RB16(src
+ xp
+ 2);
787 x
= AV_RL16(src
+ xp
+ 0);
788 y
= AV_RL16(src
+ xp
+ 1);
789 z
= AV_RL16(src
+ xp
+ 2);
792 x
= c
->xyzgamma
[x
>>4];
793 y
= c
->xyzgamma
[y
>>4];
794 z
= c
->xyzgamma
[z
>>4];
796 // convert from XYZlinear to sRGBlinear
797 r
= c
->xyz2rgb_matrix
[0][0] * x
+
798 c
->xyz2rgb_matrix
[0][1] * y
+
799 c
->xyz2rgb_matrix
[0][2] * z
>> 12;
800 g
= c
->xyz2rgb_matrix
[1][0] * x
+
801 c
->xyz2rgb_matrix
[1][1] * y
+
802 c
->xyz2rgb_matrix
[1][2] * z
>> 12;
803 b
= c
->xyz2rgb_matrix
[2][0] * x
+
804 c
->xyz2rgb_matrix
[2][1] * y
+
805 c
->xyz2rgb_matrix
[2][2] * z
>> 12;
807 // limit values to 12-bit depth
808 r
= av_clip(r
, 0, 4095);
809 g
= av_clip(g
, 0, 4095);
810 b
= av_clip(b
, 0, 4095);
812 // convert from sRGBlinear to RGB and scale from 12bit to 16bit
813 if (desc
->flags
& AV_PIX_FMT_FLAG_BE
) {
814 AV_WB16(dst
+ xp
+ 0, c
->rgbgamma
[r
] << 4);
815 AV_WB16(dst
+ xp
+ 1, c
->rgbgamma
[g
] << 4);
816 AV_WB16(dst
+ xp
+ 2, c
->rgbgamma
[b
] << 4);
818 AV_WL16(dst
+ xp
+ 0, c
->rgbgamma
[r
] << 4);
819 AV_WL16(dst
+ xp
+ 1, c
->rgbgamma
[g
] << 4);
820 AV_WL16(dst
+ xp
+ 2, c
->rgbgamma
[b
] << 4);
828 static void rgb48Toxyz12(struct SwsContext
*c
, uint16_t *dst
,
829 const uint16_t *src
, int stride
, int h
)
832 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(c
->dstFormat
);
834 for (yp
=0; yp
<h
; yp
++) {
835 for (xp
=0; xp
+2<stride
; xp
+=3) {
836 int x
, y
, z
, r
, g
, b
;
838 if (desc
->flags
& AV_PIX_FMT_FLAG_BE
) {
839 r
= AV_RB16(src
+ xp
+ 0);
840 g
= AV_RB16(src
+ xp
+ 1);
841 b
= AV_RB16(src
+ xp
+ 2);
843 r
= AV_RL16(src
+ xp
+ 0);
844 g
= AV_RL16(src
+ xp
+ 1);
845 b
= AV_RL16(src
+ xp
+ 2);
848 r
= c
->rgbgammainv
[r
>>4];
849 g
= c
->rgbgammainv
[g
>>4];
850 b
= c
->rgbgammainv
[b
>>4];
852 // convert from sRGBlinear to XYZlinear
853 x
= c
->rgb2xyz_matrix
[0][0] * r
+
854 c
->rgb2xyz_matrix
[0][1] * g
+
855 c
->rgb2xyz_matrix
[0][2] * b
>> 12;
856 y
= c
->rgb2xyz_matrix
[1][0] * r
+
857 c
->rgb2xyz_matrix
[1][1] * g
+
858 c
->rgb2xyz_matrix
[1][2] * b
>> 12;
859 z
= c
->rgb2xyz_matrix
[2][0] * r
+
860 c
->rgb2xyz_matrix
[2][1] * g
+
861 c
->rgb2xyz_matrix
[2][2] * b
>> 12;
863 // limit values to 12-bit depth
864 x
= av_clip(x
, 0, 4095);
865 y
= av_clip(y
, 0, 4095);
866 z
= av_clip(z
, 0, 4095);
868 // convert from XYZlinear to X'Y'Z' and scale from 12bit to 16bit
869 if (desc
->flags
& AV_PIX_FMT_FLAG_BE
) {
870 AV_WB16(dst
+ xp
+ 0, c
->xyzgammainv
[x
] << 4);
871 AV_WB16(dst
+ xp
+ 1, c
->xyzgammainv
[y
] << 4);
872 AV_WB16(dst
+ xp
+ 2, c
->xyzgammainv
[z
] << 4);
874 AV_WL16(dst
+ xp
+ 0, c
->xyzgammainv
[x
] << 4);
875 AV_WL16(dst
+ xp
+ 1, c
->xyzgammainv
[y
] << 4);
876 AV_WL16(dst
+ xp
+ 2, c
->xyzgammainv
[z
] << 4);
885 * swscale wrapper, so we don't need to export the SwsContext.
886 * Assumes planar YUV to be in YUV order instead of YVU.
888 int attribute_align_arg
sws_scale(struct SwsContext
*c
,
889 const uint8_t * const srcSlice
[],
890 const int srcStride
[], int srcSliceY
,
891 int srcSliceH
, uint8_t *const dst
[],
892 const int dstStride
[])
895 const uint8_t *src2
[4];
897 uint8_t *rgb0_tmp
= NULL
;
899 if (!srcStride
|| !dstStride
|| !dst
|| !srcSlice
) {
900 av_log(c
, AV_LOG_ERROR
, "One of the input parameters to sws_scale() is NULL, please check the calling code\n");
903 if (c
->cascaded_context
[0] && srcSliceY
== 0 && srcSliceH
== c
->cascaded_context
[0]->srcH
) {
904 ret
= sws_scale(c
->cascaded_context
[0],
905 srcSlice
, srcStride
, srcSliceY
, srcSliceH
,
906 c
->cascaded_tmp
, c
->cascaded_tmpStride
);
909 ret
= sws_scale(c
->cascaded_context
[1],
910 (const uint8_t * const * )c
->cascaded_tmp
, c
->cascaded_tmpStride
, 0, c
->cascaded_context
[0]->dstH
,
915 memcpy(src2
, srcSlice
, sizeof(src2
));
916 memcpy(dst2
, dst
, sizeof(dst2
));
918 // do not mess up sliceDir if we have a "trailing" 0-size slice
922 if (!check_image_pointers(srcSlice
, c
->srcFormat
, srcStride
)) {
923 av_log(c
, AV_LOG_ERROR
, "bad src image pointers\n");
926 if (!check_image_pointers((const uint8_t* const*)dst
, c
->dstFormat
, dstStride
)) {
927 av_log(c
, AV_LOG_ERROR
, "bad dst image pointers\n");
931 if (c
->sliceDir
== 0 && srcSliceY
!= 0 && srcSliceY
+ srcSliceH
!= c
->srcH
) {
932 av_log(c
, AV_LOG_ERROR
, "Slices start in the middle!\n");
935 if (c
->sliceDir
== 0) {
936 if (srcSliceY
== 0) c
->sliceDir
= 1; else c
->sliceDir
= -1;
939 if (usePal(c
->srcFormat
)) {
940 for (i
= 0; i
< 256; i
++) {
941 int r
, g
, b
, y
, u
, v
, a
= 0xff;
942 if (c
->srcFormat
== AV_PIX_FMT_PAL8
) {
943 uint32_t p
= ((const uint32_t *)(srcSlice
[1]))[i
];
944 a
= (p
>> 24) & 0xFF;
945 r
= (p
>> 16) & 0xFF;
948 } else if (c
->srcFormat
== AV_PIX_FMT_RGB8
) {
950 g
= ((i
>> 2) & 7) * 36;
952 } else if (c
->srcFormat
== AV_PIX_FMT_BGR8
) {
954 g
= ((i
>> 3) & 7) * 36;
956 } else if (c
->srcFormat
== AV_PIX_FMT_RGB4_BYTE
) {
957 r
= ( i
>> 3 ) * 255;
958 g
= ((i
>> 1) & 3) * 85;
960 } else if (c
->srcFormat
== AV_PIX_FMT_GRAY8
|| c
->srcFormat
== AV_PIX_FMT_GRAY8A
) {
963 av_assert1(c
->srcFormat
== AV_PIX_FMT_BGR4_BYTE
);
964 b
= ( i
>> 3 ) * 255;
965 g
= ((i
>> 1) & 3) * 85;
968 #define RGB2YUV_SHIFT 15
969 #define BY ( (int) (0.114 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
970 #define BV (-(int) (0.081 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
971 #define BU ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
972 #define GY ( (int) (0.587 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
973 #define GV (-(int) (0.419 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
974 #define GU (-(int) (0.331 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
975 #define RY ( (int) (0.299 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
976 #define RV ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
977 #define RU (-(int) (0.169 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
979 y
= av_clip_uint8((RY
* r
+ GY
* g
+ BY
* b
+ ( 33 << (RGB2YUV_SHIFT
- 1))) >> RGB2YUV_SHIFT
);
980 u
= av_clip_uint8((RU
* r
+ GU
* g
+ BU
* b
+ (257 << (RGB2YUV_SHIFT
- 1))) >> RGB2YUV_SHIFT
);
981 v
= av_clip_uint8((RV
* r
+ GV
* g
+ BV
* b
+ (257 << (RGB2YUV_SHIFT
- 1))) >> RGB2YUV_SHIFT
);
982 c
->pal_yuv
[i
]= y
+ (u
<<8) + (v
<<16) + ((unsigned)a
<<24);
984 switch (c
->dstFormat
) {
985 case AV_PIX_FMT_BGR32
:
987 case AV_PIX_FMT_RGB24
:
989 c
->pal_rgb
[i
]= r
+ (g
<<8) + (b
<<16) + ((unsigned)a
<<24);
991 case AV_PIX_FMT_BGR32_1
:
993 case AV_PIX_FMT_BGR24
:
995 c
->pal_rgb
[i
]= a
+ (r
<<8) + (g
<<16) + ((unsigned)b
<<24);
997 case AV_PIX_FMT_RGB32_1
:
999 case AV_PIX_FMT_RGB24
:
1001 c
->pal_rgb
[i
]= a
+ (b
<<8) + (g
<<16) + ((unsigned)r
<<24);
1003 case AV_PIX_FMT_RGB32
:
1005 case AV_PIX_FMT_BGR24
:
1008 c
->pal_rgb
[i
]= b
+ (g
<<8) + (r
<<16) + ((unsigned)a
<<24);
1013 if (c
->src0Alpha
&& !c
->dst0Alpha
&& isALPHA(c
->dstFormat
)) {
1016 rgb0_tmp
= av_malloc(FFABS(srcStride
[0]) * srcSliceH
+ 32);
1018 return AVERROR(ENOMEM
);
1020 base
= srcStride
[0] < 0 ? rgb0_tmp
- srcStride
[0] * (srcSliceH
-1) : rgb0_tmp
;
1021 for (y
=0; y
<srcSliceH
; y
++){
1022 memcpy(base
+ srcStride
[0]*y
, src2
[0] + srcStride
[0]*y
, 4*c
->srcW
);
1023 for (x
=c
->src0Alpha
-1; x
<4*c
->srcW
; x
+=4) {
1024 base
[ srcStride
[0]*y
+ x
] = 0xFF;
1030 if (c
->srcXYZ
&& !(c
->dstXYZ
&& c
->srcW
==c
->dstW
&& c
->srcH
==c
->dstH
)) {
1032 rgb0_tmp
= av_malloc(FFABS(srcStride
[0]) * srcSliceH
+ 32);
1034 return AVERROR(ENOMEM
);
1036 base
= srcStride
[0] < 0 ? rgb0_tmp
- srcStride
[0] * (srcSliceH
-1) : rgb0_tmp
;
1038 xyz12Torgb48(c
, (uint16_t*)base
, (const uint16_t*)src2
[0], srcStride
[0]/2, srcSliceH
);
1042 if (!srcSliceY
&& (c
->flags
& SWS_BITEXACT
) && c
->dither
== SWS_DITHER_ED
&& c
->dither_error
[0])
1043 for (i
= 0; i
< 4; i
++)
1044 memset(c
->dither_error
[i
], 0, sizeof(c
->dither_error
[0][0]) * (c
->dstW
+2));
1047 // copy strides, so they can safely be modified
1048 if (c
->sliceDir
== 1) {
1049 // slices go from top to bottom
1050 int srcStride2
[4] = { srcStride
[0], srcStride
[1], srcStride
[2],
1052 int dstStride2
[4] = { dstStride
[0], dstStride
[1], dstStride
[2],
1055 reset_ptr(src2
, c
->srcFormat
);
1056 reset_ptr((void*)dst2
, c
->dstFormat
);
1058 /* reset slice direction at end of frame */
1059 if (srcSliceY
+ srcSliceH
== c
->srcH
)
1062 ret
= c
->swscale(c
, src2
, srcStride2
, srcSliceY
, srcSliceH
, dst2
,
1065 // slices go from bottom to top => we flip the image internally
1066 int srcStride2
[4] = { -srcStride
[0], -srcStride
[1], -srcStride
[2],
1068 int dstStride2
[4] = { -dstStride
[0], -dstStride
[1], -dstStride
[2],
1071 src2
[0] += (srcSliceH
- 1) * srcStride
[0];
1072 if (!usePal(c
->srcFormat
))
1073 src2
[1] += ((srcSliceH
>> c
->chrSrcVSubSample
) - 1) * srcStride
[1];
1074 src2
[2] += ((srcSliceH
>> c
->chrSrcVSubSample
) - 1) * srcStride
[2];
1075 src2
[3] += (srcSliceH
- 1) * srcStride
[3];
1076 dst2
[0] += ( c
->dstH
- 1) * dstStride
[0];
1077 dst2
[1] += ((c
->dstH
>> c
->chrDstVSubSample
) - 1) * dstStride
[1];
1078 dst2
[2] += ((c
->dstH
>> c
->chrDstVSubSample
) - 1) * dstStride
[2];
1079 dst2
[3] += ( c
->dstH
- 1) * dstStride
[3];
1081 reset_ptr(src2
, c
->srcFormat
);
1082 reset_ptr((void*)dst2
, c
->dstFormat
);
1084 /* reset slice direction at end of frame */
1088 ret
= c
->swscale(c
, src2
, srcStride2
, c
->srcH
-srcSliceY
-srcSliceH
,
1089 srcSliceH
, dst2
, dstStride2
);
1093 if (c
->dstXYZ
&& !(c
->srcXYZ
&& c
->srcW
==c
->dstW
&& c
->srcH
==c
->dstH
)) {
1094 /* replace on the same data */
1095 rgb48Toxyz12(c
, (uint16_t*)dst2
[0], (const uint16_t*)dst2
[0], dstStride
[0]/2, ret
);