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/intreadwrite.h"
31 #include "libavutil/mathematics.h"
32 #include "libavutil/pixdesc.h"
35 #include "swscale_internal.h"
38 DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_128
)[9][8] = {
39 { 36, 68, 60, 92, 34, 66, 58, 90, },
40 { 100, 4, 124, 28, 98, 2, 122, 26, },
41 { 52, 84, 44, 76, 50, 82, 42, 74, },
42 { 116, 20, 108, 12, 114, 18, 106, 10, },
43 { 32, 64, 56, 88, 38, 70, 62, 94, },
44 { 96, 0, 120, 24, 102, 6, 126, 30, },
45 { 48, 80, 40, 72, 54, 86, 46, 78, },
46 { 112, 16, 104, 8, 118, 22, 110, 14, },
47 { 36, 68, 60, 92, 34, 66, 58, 90, },
50 DECLARE_ALIGNED(8, static const uint8_t, sws_pb_64
)[8] = {
51 64, 64, 64, 64, 64, 64, 64, 64
54 static av_always_inline
void fillPlane(uint8_t *plane
, int stride
, int width
,
55 int height
, int y
, uint8_t val
)
58 uint8_t *ptr
= plane
+ stride
* y
;
59 for (i
= 0; i
< height
; i
++) {
60 memset(ptr
, val
, width
);
65 static void hScale16To19_c(SwsContext
*c
, int16_t *_dst
, int dstW
,
66 const uint8_t *_src
, const int16_t *filter
,
67 const int32_t *filterPos
, int filterSize
)
69 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(c
->srcFormat
);
71 int32_t *dst
= (int32_t *) _dst
;
72 const uint16_t *src
= (const uint16_t *) _src
;
73 int bits
= desc
->comp
[0].depth_minus1
;
76 if((isAnyRGB(c
->srcFormat
) || c
->srcFormat
==AV_PIX_FMT_PAL8
) && desc
->comp
[0].depth_minus1
<15)
79 for (i
= 0; i
< dstW
; i
++) {
81 int srcPos
= filterPos
[i
];
84 for (j
= 0; j
< filterSize
; j
++) {
85 val
+= src
[srcPos
+ j
] * filter
[filterSize
* i
+ j
];
87 // filter=14 bit, input=16 bit, output=30 bit, >> 11 makes 19 bit
88 dst
[i
] = FFMIN(val
>> sh
, (1 << 19) - 1);
92 static void hScale16To15_c(SwsContext
*c
, int16_t *dst
, int dstW
,
93 const uint8_t *_src
, const int16_t *filter
,
94 const int32_t *filterPos
, int filterSize
)
96 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(c
->srcFormat
);
98 const uint16_t *src
= (const uint16_t *) _src
;
99 int sh
= desc
->comp
[0].depth_minus1
;
102 sh
= isAnyRGB(c
->srcFormat
) || c
->srcFormat
==AV_PIX_FMT_PAL8
? 13 : desc
->comp
[0].depth_minus1
;
104 for (i
= 0; i
< dstW
; i
++) {
106 int srcPos
= filterPos
[i
];
109 for (j
= 0; j
< filterSize
; j
++) {
110 val
+= src
[srcPos
+ j
] * filter
[filterSize
* i
+ j
];
112 // filter=14 bit, input=16 bit, output=30 bit, >> 15 makes 15 bit
113 dst
[i
] = FFMIN(val
>> sh
, (1 << 15) - 1);
117 // bilinear / bicubic scaling
118 static void hScale8To15_c(SwsContext
*c
, int16_t *dst
, int dstW
,
119 const uint8_t *src
, const int16_t *filter
,
120 const int32_t *filterPos
, int filterSize
)
123 for (i
= 0; i
< dstW
; i
++) {
125 int srcPos
= filterPos
[i
];
127 for (j
= 0; j
< filterSize
; j
++) {
128 val
+= ((int)src
[srcPos
+ j
]) * filter
[filterSize
* i
+ j
];
130 dst
[i
] = FFMIN(val
>> 7, (1 << 15) - 1); // the cubic equation does overflow ...
134 static void hScale8To19_c(SwsContext
*c
, int16_t *_dst
, int dstW
,
135 const uint8_t *src
, const int16_t *filter
,
136 const int32_t *filterPos
, int filterSize
)
139 int32_t *dst
= (int32_t *) _dst
;
140 for (i
= 0; i
< dstW
; i
++) {
142 int srcPos
= filterPos
[i
];
144 for (j
= 0; j
< filterSize
; j
++) {
145 val
+= ((int)src
[srcPos
+ j
]) * filter
[filterSize
* i
+ j
];
147 dst
[i
] = FFMIN(val
>> 3, (1 << 19) - 1); // the cubic equation does overflow ...
151 // FIXME all pal and rgb srcFormats could do this conversion as well
152 // FIXME all scalers more complex than bilinear could do half of this transform
153 static void chrRangeToJpeg_c(int16_t *dstU
, int16_t *dstV
, int width
)
156 for (i
= 0; i
< width
; i
++) {
157 dstU
[i
] = (FFMIN(dstU
[i
], 30775) * 4663 - 9289992) >> 12; // -264
158 dstV
[i
] = (FFMIN(dstV
[i
], 30775) * 4663 - 9289992) >> 12; // -264
162 static void chrRangeFromJpeg_c(int16_t *dstU
, int16_t *dstV
, int width
)
165 for (i
= 0; i
< width
; i
++) {
166 dstU
[i
] = (dstU
[i
] * 1799 + 4081085) >> 11; // 1469
167 dstV
[i
] = (dstV
[i
] * 1799 + 4081085) >> 11; // 1469
171 static void lumRangeToJpeg_c(int16_t *dst
, int width
)
174 for (i
= 0; i
< width
; i
++)
175 dst
[i
] = (FFMIN(dst
[i
], 30189) * 19077 - 39057361) >> 14;
178 static void lumRangeFromJpeg_c(int16_t *dst
, int width
)
181 for (i
= 0; i
< width
; i
++)
182 dst
[i
] = (dst
[i
] * 14071 + 33561947) >> 14;
185 static void chrRangeToJpeg16_c(int16_t *_dstU
, int16_t *_dstV
, int width
)
188 int32_t *dstU
= (int32_t *) _dstU
;
189 int32_t *dstV
= (int32_t *) _dstV
;
190 for (i
= 0; i
< width
; i
++) {
191 dstU
[i
] = (FFMIN(dstU
[i
], 30775 << 4) * 4663 - (9289992 << 4)) >> 12; // -264
192 dstV
[i
] = (FFMIN(dstV
[i
], 30775 << 4) * 4663 - (9289992 << 4)) >> 12; // -264
196 static void chrRangeFromJpeg16_c(int16_t *_dstU
, int16_t *_dstV
, int width
)
199 int32_t *dstU
= (int32_t *) _dstU
;
200 int32_t *dstV
= (int32_t *) _dstV
;
201 for (i
= 0; i
< width
; i
++) {
202 dstU
[i
] = (dstU
[i
] * 1799 + (4081085 << 4)) >> 11; // 1469
203 dstV
[i
] = (dstV
[i
] * 1799 + (4081085 << 4)) >> 11; // 1469
207 static void lumRangeToJpeg16_c(int16_t *_dst
, int width
)
210 int32_t *dst
= (int32_t *) _dst
;
211 for (i
= 0; i
< width
; i
++) {
212 dst
[i
] = ((int)(FFMIN(dst
[i
], 30189 << 4) * 4769U - (39057361 << 2))) >> 12;
216 static void lumRangeFromJpeg16_c(int16_t *_dst
, int width
)
219 int32_t *dst
= (int32_t *) _dst
;
220 for (i
= 0; i
< width
; i
++)
221 dst
[i
] = (dst
[i
]*(14071/4) + (33561947<<4)/4)>>12;
224 // *** horizontal scale Y line to temp buffer
225 static av_always_inline
void hyscale(SwsContext
*c
, int16_t *dst
, int dstWidth
,
226 const uint8_t *src_in
[4],
228 const int16_t *hLumFilter
,
229 const int32_t *hLumFilterPos
,
231 uint8_t *formatConvBuffer
,
232 uint32_t *pal
, int isAlpha
)
234 void (*toYV12
)(uint8_t *, const uint8_t *, const uint8_t *, const uint8_t *, int, uint32_t *) =
235 isAlpha
? c
->alpToYV12
: c
->lumToYV12
;
236 void (*convertRange
)(int16_t *, int) = isAlpha
? NULL
: c
->lumConvertRange
;
237 const uint8_t *src
= src_in
[isAlpha
? 3 : 0];
240 toYV12(formatConvBuffer
, src
, src_in
[1], src_in
[2], srcW
, pal
);
241 src
= formatConvBuffer
;
242 } else if (c
->readLumPlanar
&& !isAlpha
) {
243 c
->readLumPlanar(formatConvBuffer
, src_in
, srcW
, c
->input_rgb2yuv_table
);
244 src
= formatConvBuffer
;
245 } else if (c
->readAlpPlanar
&& isAlpha
) {
246 c
->readAlpPlanar(formatConvBuffer
, src_in
, srcW
, NULL
);
247 src
= formatConvBuffer
;
250 if (!c
->hyscale_fast
) {
251 c
->hyScale(c
, dst
, dstWidth
, src
, hLumFilter
,
252 hLumFilterPos
, hLumFilterSize
);
253 } else { // fast bilinear upscale / crap downscale
254 c
->hyscale_fast(c
, dst
, dstWidth
, src
, srcW
, xInc
);
258 convertRange(dst
, dstWidth
);
261 static av_always_inline
void hcscale(SwsContext
*c
, int16_t *dst1
,
262 int16_t *dst2
, int dstWidth
,
263 const uint8_t *src_in
[4],
265 const int16_t *hChrFilter
,
266 const int32_t *hChrFilterPos
,
268 uint8_t *formatConvBuffer
, uint32_t *pal
)
270 const uint8_t *src1
= src_in
[1], *src2
= src_in
[2];
272 uint8_t *buf2
= formatConvBuffer
+
273 FFALIGN(srcW
*2+78, 16);
274 c
->chrToYV12(formatConvBuffer
, buf2
, src_in
[0], src1
, src2
, srcW
, pal
);
275 src1
= formatConvBuffer
;
277 } else if (c
->readChrPlanar
) {
278 uint8_t *buf2
= formatConvBuffer
+
279 FFALIGN(srcW
*2+78, 16);
280 c
->readChrPlanar(formatConvBuffer
, buf2
, src_in
, srcW
, c
->input_rgb2yuv_table
);
281 src1
= formatConvBuffer
;
285 if (!c
->hcscale_fast
) {
286 c
->hcScale(c
, dst1
, dstWidth
, src1
, hChrFilter
, hChrFilterPos
, hChrFilterSize
);
287 c
->hcScale(c
, dst2
, dstWidth
, src2
, hChrFilter
, hChrFilterPos
, hChrFilterSize
);
288 } else { // fast bilinear upscale / crap downscale
289 c
->hcscale_fast(c
, dst1
, dst2
, dstWidth
, src1
, src2
, srcW
, xInc
);
292 if (c
->chrConvertRange
)
293 c
->chrConvertRange(dst1
, dst2
, dstWidth
);
296 #define DEBUG_SWSCALE_BUFFERS 0
297 #define DEBUG_BUFFERS(...) \
298 if (DEBUG_SWSCALE_BUFFERS) \
299 av_log(c, AV_LOG_DEBUG, __VA_ARGS__)
301 static int swscale(SwsContext
*c
, const uint8_t *src
[],
302 int srcStride
[], int srcSliceY
,
303 int srcSliceH
, uint8_t *dst
[], int dstStride
[])
305 /* load a few things into local vars to make the code more readable?
307 const int srcW
= c
->srcW
;
308 const int dstW
= c
->dstW
;
309 const int dstH
= c
->dstH
;
310 const int chrDstW
= c
->chrDstW
;
311 const int chrSrcW
= c
->chrSrcW
;
312 const int lumXInc
= c
->lumXInc
;
313 const int chrXInc
= c
->chrXInc
;
314 const enum AVPixelFormat dstFormat
= c
->dstFormat
;
315 const int flags
= c
->flags
;
316 int32_t *vLumFilterPos
= c
->vLumFilterPos
;
317 int32_t *vChrFilterPos
= c
->vChrFilterPos
;
318 int32_t *hLumFilterPos
= c
->hLumFilterPos
;
319 int32_t *hChrFilterPos
= c
->hChrFilterPos
;
320 int16_t *hLumFilter
= c
->hLumFilter
;
321 int16_t *hChrFilter
= c
->hChrFilter
;
322 int32_t *lumMmxFilter
= c
->lumMmxFilter
;
323 int32_t *chrMmxFilter
= c
->chrMmxFilter
;
324 const int vLumFilterSize
= c
->vLumFilterSize
;
325 const int vChrFilterSize
= c
->vChrFilterSize
;
326 const int hLumFilterSize
= c
->hLumFilterSize
;
327 const int hChrFilterSize
= c
->hChrFilterSize
;
328 int16_t **lumPixBuf
= c
->lumPixBuf
;
329 int16_t **chrUPixBuf
= c
->chrUPixBuf
;
330 int16_t **chrVPixBuf
= c
->chrVPixBuf
;
331 int16_t **alpPixBuf
= c
->alpPixBuf
;
332 const int vLumBufSize
= c
->vLumBufSize
;
333 const int vChrBufSize
= c
->vChrBufSize
;
334 uint8_t *formatConvBuffer
= c
->formatConvBuffer
;
335 uint32_t *pal
= c
->pal_yuv
;
336 yuv2planar1_fn yuv2plane1
= c
->yuv2plane1
;
337 yuv2planarX_fn yuv2planeX
= c
->yuv2planeX
;
338 yuv2interleavedX_fn yuv2nv12cX
= c
->yuv2nv12cX
;
339 yuv2packed1_fn yuv2packed1
= c
->yuv2packed1
;
340 yuv2packed2_fn yuv2packed2
= c
->yuv2packed2
;
341 yuv2packedX_fn yuv2packedX
= c
->yuv2packedX
;
342 yuv2anyX_fn yuv2anyX
= c
->yuv2anyX
;
343 const int chrSrcSliceY
= srcSliceY
>> c
->chrSrcVSubSample
;
344 const int chrSrcSliceH
= FF_CEIL_RSHIFT(srcSliceH
, c
->chrSrcVSubSample
);
345 int should_dither
= is9_OR_10BPS(c
->srcFormat
) ||
346 is16BPS(c
->srcFormat
);
349 /* vars which will change and which we need to store back in the context */
351 int lumBufIndex
= c
->lumBufIndex
;
352 int chrBufIndex
= c
->chrBufIndex
;
353 int lastInLumBuf
= c
->lastInLumBuf
;
354 int lastInChrBuf
= c
->lastInChrBuf
;
356 if (!usePal(c
->srcFormat
)) {
357 pal
= c
->input_rgb2yuv_table
;
360 if (isPacked(c
->srcFormat
)) {
368 srcStride
[3] = srcStride
[0];
370 srcStride
[1] <<= c
->vChrDrop
;
371 srcStride
[2] <<= c
->vChrDrop
;
373 DEBUG_BUFFERS("swscale() %p[%d] %p[%d] %p[%d] %p[%d] -> %p[%d] %p[%d] %p[%d] %p[%d]\n",
374 src
[0], srcStride
[0], src
[1], srcStride
[1],
375 src
[2], srcStride
[2], src
[3], srcStride
[3],
376 dst
[0], dstStride
[0], dst
[1], dstStride
[1],
377 dst
[2], dstStride
[2], dst
[3], dstStride
[3]);
378 DEBUG_BUFFERS("srcSliceY: %d srcSliceH: %d dstY: %d dstH: %d\n",
379 srcSliceY
, srcSliceH
, dstY
, dstH
);
380 DEBUG_BUFFERS("vLumFilterSize: %d vLumBufSize: %d vChrFilterSize: %d vChrBufSize: %d\n",
381 vLumFilterSize
, vLumBufSize
, vChrFilterSize
, vChrBufSize
);
383 if (dstStride
[0]&15 || dstStride
[1]&15 ||
384 dstStride
[2]&15 || dstStride
[3]&15) {
385 static int warnedAlready
= 0; // FIXME maybe move this into the context
386 if (flags
& SWS_PRINT_INFO
&& !warnedAlready
) {
387 av_log(c
, AV_LOG_WARNING
,
388 "Warning: dstStride is not aligned!\n"
389 " ->cannot do aligned memory accesses anymore\n");
394 if ( (uintptr_t)dst
[0]&15 || (uintptr_t)dst
[1]&15 || (uintptr_t)dst
[2]&15
395 || (uintptr_t)src
[0]&15 || (uintptr_t)src
[1]&15 || (uintptr_t)src
[2]&15
396 || dstStride
[0]&15 || dstStride
[1]&15 || dstStride
[2]&15 || dstStride
[3]&15
397 || srcStride
[0]&15 || srcStride
[1]&15 || srcStride
[2]&15 || srcStride
[3]&15
399 static int warnedAlready
=0;
400 int cpu_flags
= av_get_cpu_flags();
401 if (HAVE_MMXEXT
&& (cpu_flags
& AV_CPU_FLAG_SSE2
) && !warnedAlready
){
402 av_log(c
, AV_LOG_WARNING
, "Warning: data is not aligned! This can lead to a speedloss\n");
407 /* Note the user might start scaling the picture in the middle so this
408 * will not get executed. This is not really intended but works
409 * currently, so people might do it. */
410 if (srcSliceY
== 0) {
418 if (!should_dither
) {
419 c
->chrDither8
= c
->lumDither8
= sws_pb_64
;
423 for (; dstY
< dstH
; dstY
++) {
424 const int chrDstY
= dstY
>> c
->chrDstVSubSample
;
426 dst
[0] + dstStride
[0] * dstY
,
427 dst
[1] + dstStride
[1] * chrDstY
,
428 dst
[2] + dstStride
[2] * chrDstY
,
429 (CONFIG_SWSCALE_ALPHA
&& alpPixBuf
) ? dst
[3] + dstStride
[3] * dstY
: NULL
,
431 int use_mmx_vfilter
= c
->use_mmx_vfilter
;
433 // First line needed as input
434 const int firstLumSrcY
= FFMAX(1 - vLumFilterSize
, vLumFilterPos
[dstY
]);
435 const int firstLumSrcY2
= FFMAX(1 - vLumFilterSize
, vLumFilterPos
[FFMIN(dstY
| ((1 << c
->chrDstVSubSample
) - 1), dstH
- 1)]);
436 // First line needed as input
437 const int firstChrSrcY
= FFMAX(1 - vChrFilterSize
, vChrFilterPos
[chrDstY
]);
439 // Last line needed as input
440 int lastLumSrcY
= FFMIN(c
->srcH
, firstLumSrcY
+ vLumFilterSize
) - 1;
441 int lastLumSrcY2
= FFMIN(c
->srcH
, firstLumSrcY2
+ vLumFilterSize
) - 1;
442 int lastChrSrcY
= FFMIN(c
->chrSrcH
, firstChrSrcY
+ vChrFilterSize
) - 1;
445 // handle holes (FAST_BILINEAR & weird filters)
446 if (firstLumSrcY
> lastInLumBuf
)
447 lastInLumBuf
= firstLumSrcY
- 1;
448 if (firstChrSrcY
> lastInChrBuf
)
449 lastInChrBuf
= firstChrSrcY
- 1;
450 av_assert0(firstLumSrcY
>= lastInLumBuf
- vLumBufSize
+ 1);
451 av_assert0(firstChrSrcY
>= lastInChrBuf
- vChrBufSize
+ 1);
453 DEBUG_BUFFERS("dstY: %d\n", dstY
);
454 DEBUG_BUFFERS("\tfirstLumSrcY: %d lastLumSrcY: %d lastInLumBuf: %d\n",
455 firstLumSrcY
, lastLumSrcY
, lastInLumBuf
);
456 DEBUG_BUFFERS("\tfirstChrSrcY: %d lastChrSrcY: %d lastInChrBuf: %d\n",
457 firstChrSrcY
, lastChrSrcY
, lastInChrBuf
);
459 // Do we have enough lines in this slice to output the dstY line
460 enough_lines
= lastLumSrcY2
< srcSliceY
+ srcSliceH
&&
461 lastChrSrcY
< FF_CEIL_RSHIFT(srcSliceY
+ srcSliceH
, c
->chrSrcVSubSample
);
464 lastLumSrcY
= srcSliceY
+ srcSliceH
- 1;
465 lastChrSrcY
= chrSrcSliceY
+ chrSrcSliceH
- 1;
466 DEBUG_BUFFERS("buffering slice: lastLumSrcY %d lastChrSrcY %d\n",
467 lastLumSrcY
, lastChrSrcY
);
470 // Do horizontal scaling
471 while (lastInLumBuf
< lastLumSrcY
) {
472 const uint8_t *src1
[4] = {
473 src
[0] + (lastInLumBuf
+ 1 - srcSliceY
) * srcStride
[0],
474 src
[1] + (lastInLumBuf
+ 1 - srcSliceY
) * srcStride
[1],
475 src
[2] + (lastInLumBuf
+ 1 - srcSliceY
) * srcStride
[2],
476 src
[3] + (lastInLumBuf
+ 1 - srcSliceY
) * srcStride
[3],
479 av_assert0(lumBufIndex
< 2 * vLumBufSize
);
480 av_assert0(lastInLumBuf
+ 1 - srcSliceY
< srcSliceH
);
481 av_assert0(lastInLumBuf
+ 1 - srcSliceY
>= 0);
482 hyscale(c
, lumPixBuf
[lumBufIndex
], dstW
, src1
, srcW
, lumXInc
,
483 hLumFilter
, hLumFilterPos
, hLumFilterSize
,
484 formatConvBuffer
, pal
, 0);
485 if (CONFIG_SWSCALE_ALPHA
&& alpPixBuf
)
486 hyscale(c
, alpPixBuf
[lumBufIndex
], dstW
, src1
, srcW
,
487 lumXInc
, hLumFilter
, hLumFilterPos
, hLumFilterSize
,
488 formatConvBuffer
, pal
, 1);
490 DEBUG_BUFFERS("\t\tlumBufIndex %d: lastInLumBuf: %d\n",
491 lumBufIndex
, lastInLumBuf
);
493 while (lastInChrBuf
< lastChrSrcY
) {
494 const uint8_t *src1
[4] = {
495 src
[0] + (lastInChrBuf
+ 1 - chrSrcSliceY
) * srcStride
[0],
496 src
[1] + (lastInChrBuf
+ 1 - chrSrcSliceY
) * srcStride
[1],
497 src
[2] + (lastInChrBuf
+ 1 - chrSrcSliceY
) * srcStride
[2],
498 src
[3] + (lastInChrBuf
+ 1 - chrSrcSliceY
) * srcStride
[3],
501 av_assert0(chrBufIndex
< 2 * vChrBufSize
);
502 av_assert0(lastInChrBuf
+ 1 - chrSrcSliceY
< (chrSrcSliceH
));
503 av_assert0(lastInChrBuf
+ 1 - chrSrcSliceY
>= 0);
504 // FIXME replace parameters through context struct (some at least)
506 if (c
->needs_hcscale
)
507 hcscale(c
, chrUPixBuf
[chrBufIndex
], chrVPixBuf
[chrBufIndex
],
508 chrDstW
, src1
, chrSrcW
, chrXInc
,
509 hChrFilter
, hChrFilterPos
, hChrFilterSize
,
510 formatConvBuffer
, pal
);
512 DEBUG_BUFFERS("\t\tchrBufIndex %d: lastInChrBuf: %d\n",
513 chrBufIndex
, lastInChrBuf
);
515 // wrap buf index around to stay inside the ring buffer
516 if (lumBufIndex
>= vLumBufSize
)
517 lumBufIndex
-= vLumBufSize
;
518 if (chrBufIndex
>= vChrBufSize
)
519 chrBufIndex
-= vChrBufSize
;
521 break; // we can't output a dstY line so let's try with the next slice
524 updateMMXDitherTables(c
, dstY
, lumBufIndex
, chrBufIndex
,
525 lastInLumBuf
, lastInChrBuf
);
528 c
->chrDither8
= ff_dither_8x8_128
[chrDstY
& 7];
529 c
->lumDither8
= ff_dither_8x8_128
[dstY
& 7];
531 if (dstY
>= dstH
- 2) {
532 /* hmm looks like we can't use MMX here without overwriting
533 * this array's tail */
534 ff_sws_init_output_funcs(c
, &yuv2plane1
, &yuv2planeX
, &yuv2nv12cX
,
535 &yuv2packed1
, &yuv2packed2
, &yuv2packedX
, &yuv2anyX
);
540 const int16_t **lumSrcPtr
= (const int16_t **)(void*) lumPixBuf
+ lumBufIndex
+ firstLumSrcY
- lastInLumBuf
+ vLumBufSize
;
541 const int16_t **chrUSrcPtr
= (const int16_t **)(void*) chrUPixBuf
+ chrBufIndex
+ firstChrSrcY
- lastInChrBuf
+ vChrBufSize
;
542 const int16_t **chrVSrcPtr
= (const int16_t **)(void*) chrVPixBuf
+ chrBufIndex
+ firstChrSrcY
- lastInChrBuf
+ vChrBufSize
;
543 const int16_t **alpSrcPtr
= (CONFIG_SWSCALE_ALPHA
&& alpPixBuf
) ?
544 (const int16_t **)(void*) alpPixBuf
+ lumBufIndex
+ firstLumSrcY
- lastInLumBuf
+ vLumBufSize
: NULL
;
545 int16_t *vLumFilter
= c
->vLumFilter
;
546 int16_t *vChrFilter
= c
->vChrFilter
;
548 if (isPlanarYUV(dstFormat
) ||
549 (isGray(dstFormat
) && !isALPHA(dstFormat
))) { // YV12 like
550 const int chrSkipMask
= (1 << c
->chrDstVSubSample
) - 1;
552 vLumFilter
+= dstY
* vLumFilterSize
;
553 vChrFilter
+= chrDstY
* vChrFilterSize
;
555 // av_assert0(use_mmx_vfilter != (
556 // yuv2planeX == yuv2planeX_10BE_c
557 // || yuv2planeX == yuv2planeX_10LE_c
558 // || yuv2planeX == yuv2planeX_9BE_c
559 // || yuv2planeX == yuv2planeX_9LE_c
560 // || yuv2planeX == yuv2planeX_16BE_c
561 // || yuv2planeX == yuv2planeX_16LE_c
562 // || yuv2planeX == yuv2planeX_8_c) || !ARCH_X86);
565 vLumFilter
= (int16_t *)c
->lumMmxFilter
;
566 vChrFilter
= (int16_t *)c
->chrMmxFilter
;
569 if (vLumFilterSize
== 1) {
570 yuv2plane1(lumSrcPtr
[0], dest
[0], dstW
, c
->lumDither8
, 0);
572 yuv2planeX(vLumFilter
, vLumFilterSize
,
574 dstW
, c
->lumDither8
, 0);
577 if (!((dstY
& chrSkipMask
) || isGray(dstFormat
))) {
579 yuv2nv12cX(c
, vChrFilter
,
580 vChrFilterSize
, chrUSrcPtr
, chrVSrcPtr
,
582 } else if (vChrFilterSize
== 1) {
583 yuv2plane1(chrUSrcPtr
[0], dest
[1], chrDstW
, c
->chrDither8
, 0);
584 yuv2plane1(chrVSrcPtr
[0], dest
[2], chrDstW
, c
->chrDither8
, 3);
586 yuv2planeX(vChrFilter
,
587 vChrFilterSize
, chrUSrcPtr
, dest
[1],
588 chrDstW
, c
->chrDither8
, 0);
589 yuv2planeX(vChrFilter
,
590 vChrFilterSize
, chrVSrcPtr
, dest
[2],
591 chrDstW
, c
->chrDither8
, use_mmx_vfilter
? (c
->uv_offx2
>> 1) : 3);
595 if (CONFIG_SWSCALE_ALPHA
&& alpPixBuf
) {
597 vLumFilter
= (int16_t *)c
->alpMmxFilter
;
599 if (vLumFilterSize
== 1) {
600 yuv2plane1(alpSrcPtr
[0], dest
[3], dstW
,
603 yuv2planeX(vLumFilter
,
604 vLumFilterSize
, alpSrcPtr
, dest
[3],
605 dstW
, c
->lumDither8
, 0);
608 } else if (yuv2packedX
) {
609 av_assert1(lumSrcPtr
+ vLumFilterSize
- 1 < (const int16_t **)lumPixBuf
+ vLumBufSize
* 2);
610 av_assert1(chrUSrcPtr
+ vChrFilterSize
- 1 < (const int16_t **)chrUPixBuf
+ vChrBufSize
* 2);
611 if (c
->yuv2packed1
&& vLumFilterSize
== 1 &&
612 vChrFilterSize
<= 2) { // unscaled RGB
613 int chrAlpha
= vChrFilterSize
== 1 ? 0 : vChrFilter
[2 * dstY
+ 1];
614 yuv2packed1(c
, *lumSrcPtr
, chrUSrcPtr
, chrVSrcPtr
,
615 alpPixBuf
? *alpSrcPtr
: NULL
,
616 dest
[0], dstW
, chrAlpha
, dstY
);
617 } else if (c
->yuv2packed2
&& vLumFilterSize
== 2 &&
618 vChrFilterSize
== 2) { // bilinear upscale RGB
619 int lumAlpha
= vLumFilter
[2 * dstY
+ 1];
620 int chrAlpha
= vChrFilter
[2 * dstY
+ 1];
622 lumMmxFilter
[3] = vLumFilter
[2 * dstY
] * 0x10001;
624 chrMmxFilter
[3] = vChrFilter
[2 * chrDstY
] * 0x10001;
625 yuv2packed2(c
, lumSrcPtr
, chrUSrcPtr
, chrVSrcPtr
,
626 alpPixBuf
? alpSrcPtr
: NULL
,
627 dest
[0], dstW
, lumAlpha
, chrAlpha
, dstY
);
628 } else { // general RGB
629 yuv2packedX(c
, vLumFilter
+ dstY
* vLumFilterSize
,
630 lumSrcPtr
, vLumFilterSize
,
631 vChrFilter
+ dstY
* vChrFilterSize
,
632 chrUSrcPtr
, chrVSrcPtr
, vChrFilterSize
,
633 alpSrcPtr
, dest
[0], dstW
, dstY
);
636 av_assert1(!yuv2packed1
&& !yuv2packed2
);
637 yuv2anyX(c
, vLumFilter
+ dstY
* vLumFilterSize
,
638 lumSrcPtr
, vLumFilterSize
,
639 vChrFilter
+ dstY
* vChrFilterSize
,
640 chrUSrcPtr
, chrVSrcPtr
, vChrFilterSize
,
641 alpSrcPtr
, dest
, dstW
, dstY
);
645 if (isPlanar(dstFormat
) && isALPHA(dstFormat
) && !alpPixBuf
) {
647 int height
= dstY
- lastDstY
;
649 if (is16BPS(dstFormat
) || isNBPS(dstFormat
)) {
650 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(dstFormat
);
651 fillPlane16(dst
[3], dstStride
[3], length
, height
, lastDstY
,
652 1, desc
->comp
[3].depth_minus1
,
655 fillPlane(dst
[3], dstStride
[3], length
, height
, lastDstY
, 255);
658 #if HAVE_MMXEXT_INLINE
659 if (av_get_cpu_flags() & AV_CPU_FLAG_MMXEXT
)
660 __asm__
volatile ("sfence" ::: "memory");
664 /* store changed local vars back in the context */
666 c
->lumBufIndex
= lumBufIndex
;
667 c
->chrBufIndex
= chrBufIndex
;
668 c
->lastInLumBuf
= lastInLumBuf
;
669 c
->lastInChrBuf
= lastInChrBuf
;
671 return dstY
- lastDstY
;
674 av_cold
void ff_sws_init_range_convert(SwsContext
*c
)
676 c
->lumConvertRange
= NULL
;
677 c
->chrConvertRange
= NULL
;
678 if (c
->srcRange
!= c
->dstRange
&& !isAnyRGB(c
->dstFormat
)) {
679 if (c
->dstBpc
<= 14) {
681 c
->lumConvertRange
= lumRangeFromJpeg_c
;
682 c
->chrConvertRange
= chrRangeFromJpeg_c
;
684 c
->lumConvertRange
= lumRangeToJpeg_c
;
685 c
->chrConvertRange
= chrRangeToJpeg_c
;
689 c
->lumConvertRange
= lumRangeFromJpeg16_c
;
690 c
->chrConvertRange
= chrRangeFromJpeg16_c
;
692 c
->lumConvertRange
= lumRangeToJpeg16_c
;
693 c
->chrConvertRange
= chrRangeToJpeg16_c
;
699 static av_cold
void sws_init_swscale(SwsContext
*c
)
701 enum AVPixelFormat srcFormat
= c
->srcFormat
;
703 ff_sws_init_output_funcs(c
, &c
->yuv2plane1
, &c
->yuv2planeX
,
704 &c
->yuv2nv12cX
, &c
->yuv2packed1
,
705 &c
->yuv2packed2
, &c
->yuv2packedX
, &c
->yuv2anyX
);
707 ff_sws_init_input_funcs(c
);
710 if (c
->srcBpc
== 8) {
711 if (c
->dstBpc
<= 14) {
712 c
->hyScale
= c
->hcScale
= hScale8To15_c
;
713 if (c
->flags
& SWS_FAST_BILINEAR
) {
714 c
->hyscale_fast
= ff_hyscale_fast_c
;
715 c
->hcscale_fast
= ff_hcscale_fast_c
;
718 c
->hyScale
= c
->hcScale
= hScale8To19_c
;
721 c
->hyScale
= c
->hcScale
= c
->dstBpc
> 14 ? hScale16To19_c
725 ff_sws_init_range_convert(c
);
727 if (!(isGray(srcFormat
) || isGray(c
->dstFormat
) ||
728 srcFormat
== AV_PIX_FMT_MONOBLACK
|| srcFormat
== AV_PIX_FMT_MONOWHITE
))
729 c
->needs_hcscale
= 1;
732 SwsFunc
ff_getSwsFunc(SwsContext
*c
)
737 ff_sws_init_swscale_ppc(c
);
739 ff_sws_init_swscale_x86(c
);
744 static void reset_ptr(const uint8_t *src
[], int format
)
746 if (!isALPHA(format
))
748 if (!isPlanar(format
)) {
749 src
[3] = src
[2] = NULL
;
756 static int check_image_pointers(const uint8_t * const data
[4], enum AVPixelFormat pix_fmt
,
757 const int linesizes
[4])
759 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(pix_fmt
);
762 for (i
= 0; i
< 4; i
++) {
763 int plane
= desc
->comp
[i
].plane
;
764 if (!data
[plane
] || !linesizes
[plane
])
771 static void xyz12Torgb48(struct SwsContext
*c
, uint16_t *dst
,
772 const uint16_t *src
, int stride
, int h
)
775 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(c
->srcFormat
);
777 for (yp
=0; yp
<h
; yp
++) {
778 for (xp
=0; xp
+2<stride
; xp
+=3) {
779 int x
, y
, z
, r
, g
, b
;
781 if (desc
->flags
& AV_PIX_FMT_FLAG_BE
) {
782 x
= AV_RB16(src
+ xp
+ 0);
783 y
= AV_RB16(src
+ xp
+ 1);
784 z
= AV_RB16(src
+ xp
+ 2);
786 x
= AV_RL16(src
+ xp
+ 0);
787 y
= AV_RL16(src
+ xp
+ 1);
788 z
= AV_RL16(src
+ xp
+ 2);
791 x
= c
->xyzgamma
[x
>>4];
792 y
= c
->xyzgamma
[y
>>4];
793 z
= c
->xyzgamma
[z
>>4];
795 // convert from XYZlinear to sRGBlinear
796 r
= c
->xyz2rgb_matrix
[0][0] * x
+
797 c
->xyz2rgb_matrix
[0][1] * y
+
798 c
->xyz2rgb_matrix
[0][2] * z
>> 12;
799 g
= c
->xyz2rgb_matrix
[1][0] * x
+
800 c
->xyz2rgb_matrix
[1][1] * y
+
801 c
->xyz2rgb_matrix
[1][2] * z
>> 12;
802 b
= c
->xyz2rgb_matrix
[2][0] * x
+
803 c
->xyz2rgb_matrix
[2][1] * y
+
804 c
->xyz2rgb_matrix
[2][2] * z
>> 12;
806 // limit values to 12-bit depth
807 r
= av_clip_c(r
,0,4095);
808 g
= av_clip_c(g
,0,4095);
809 b
= av_clip_c(b
,0,4095);
811 // convert from sRGBlinear to RGB and scale from 12bit to 16bit
812 if (desc
->flags
& AV_PIX_FMT_FLAG_BE
) {
813 AV_WB16(dst
+ xp
+ 0, c
->rgbgamma
[r
] << 4);
814 AV_WB16(dst
+ xp
+ 1, c
->rgbgamma
[g
] << 4);
815 AV_WB16(dst
+ xp
+ 2, c
->rgbgamma
[b
] << 4);
817 AV_WL16(dst
+ xp
+ 0, c
->rgbgamma
[r
] << 4);
818 AV_WL16(dst
+ xp
+ 1, c
->rgbgamma
[g
] << 4);
819 AV_WL16(dst
+ xp
+ 2, c
->rgbgamma
[b
] << 4);
827 static void rgb48Toxyz12(struct SwsContext
*c
, uint16_t *dst
,
828 const uint16_t *src
, int stride
, int h
)
831 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(c
->dstFormat
);
833 for (yp
=0; yp
<h
; yp
++) {
834 for (xp
=0; xp
+2<stride
; xp
+=3) {
835 int x
, y
, z
, r
, g
, b
;
837 if (desc
->flags
& AV_PIX_FMT_FLAG_BE
) {
838 r
= AV_RB16(src
+ xp
+ 0);
839 g
= AV_RB16(src
+ xp
+ 1);
840 b
= AV_RB16(src
+ xp
+ 2);
842 r
= AV_RL16(src
+ xp
+ 0);
843 g
= AV_RL16(src
+ xp
+ 1);
844 b
= AV_RL16(src
+ xp
+ 2);
847 r
= c
->rgbgammainv
[r
>>4];
848 g
= c
->rgbgammainv
[g
>>4];
849 b
= c
->rgbgammainv
[b
>>4];
851 // convert from sRGBlinear to XYZlinear
852 x
= c
->rgb2xyz_matrix
[0][0] * r
+
853 c
->rgb2xyz_matrix
[0][1] * g
+
854 c
->rgb2xyz_matrix
[0][2] * b
>> 12;
855 y
= c
->rgb2xyz_matrix
[1][0] * r
+
856 c
->rgb2xyz_matrix
[1][1] * g
+
857 c
->rgb2xyz_matrix
[1][2] * b
>> 12;
858 z
= c
->rgb2xyz_matrix
[2][0] * r
+
859 c
->rgb2xyz_matrix
[2][1] * g
+
860 c
->rgb2xyz_matrix
[2][2] * b
>> 12;
862 // limit values to 12-bit depth
863 x
= av_clip_c(x
,0,4095);
864 y
= av_clip_c(y
,0,4095);
865 z
= av_clip_c(z
,0,4095);
867 // convert from XYZlinear to X'Y'Z' and scale from 12bit to 16bit
868 if (desc
->flags
& AV_PIX_FMT_FLAG_BE
) {
869 AV_WB16(dst
+ xp
+ 0, c
->xyzgammainv
[x
] << 4);
870 AV_WB16(dst
+ xp
+ 1, c
->xyzgammainv
[y
] << 4);
871 AV_WB16(dst
+ xp
+ 2, c
->xyzgammainv
[z
] << 4);
873 AV_WL16(dst
+ xp
+ 0, c
->xyzgammainv
[x
] << 4);
874 AV_WL16(dst
+ xp
+ 1, c
->xyzgammainv
[y
] << 4);
875 AV_WL16(dst
+ xp
+ 2, c
->xyzgammainv
[z
] << 4);
884 * swscale wrapper, so we don't need to export the SwsContext.
885 * Assumes planar YUV to be in YUV order instead of YVU.
887 int attribute_align_arg
sws_scale(struct SwsContext
*c
,
888 const uint8_t * const srcSlice
[],
889 const int srcStride
[], int srcSliceY
,
890 int srcSliceH
, uint8_t *const dst
[],
891 const int dstStride
[])
894 const uint8_t *src2
[4];
896 uint8_t *rgb0_tmp
= NULL
;
898 if (!srcStride
|| !dstStride
|| !dst
|| !srcSlice
) {
899 av_log(c
, AV_LOG_ERROR
, "One of the input parameters to sws_scale() is NULL, please check the calling code\n");
902 memcpy(src2
, srcSlice
, sizeof(src2
));
903 memcpy(dst2
, dst
, sizeof(dst2
));
905 // do not mess up sliceDir if we have a "trailing" 0-size slice
909 if (!check_image_pointers(srcSlice
, c
->srcFormat
, srcStride
)) {
910 av_log(c
, AV_LOG_ERROR
, "bad src image pointers\n");
913 if (!check_image_pointers((const uint8_t* const*)dst
, c
->dstFormat
, dstStride
)) {
914 av_log(c
, AV_LOG_ERROR
, "bad dst image pointers\n");
918 if (c
->sliceDir
== 0 && srcSliceY
!= 0 && srcSliceY
+ srcSliceH
!= c
->srcH
) {
919 av_log(c
, AV_LOG_ERROR
, "Slices start in the middle!\n");
922 if (c
->sliceDir
== 0) {
923 if (srcSliceY
== 0) c
->sliceDir
= 1; else c
->sliceDir
= -1;
926 if (usePal(c
->srcFormat
)) {
927 for (i
= 0; i
< 256; i
++) {
928 int r
, g
, b
, y
, u
, v
, a
= 0xff;
929 if (c
->srcFormat
== AV_PIX_FMT_PAL8
) {
930 uint32_t p
= ((const uint32_t *)(srcSlice
[1]))[i
];
931 a
= (p
>> 24) & 0xFF;
932 r
= (p
>> 16) & 0xFF;
935 } else if (c
->srcFormat
== AV_PIX_FMT_RGB8
) {
937 g
= ((i
>> 2) & 7) * 36;
939 } else if (c
->srcFormat
== AV_PIX_FMT_BGR8
) {
941 g
= ((i
>> 3) & 7) * 36;
943 } else if (c
->srcFormat
== AV_PIX_FMT_RGB4_BYTE
) {
944 r
= ( i
>> 3 ) * 255;
945 g
= ((i
>> 1) & 3) * 85;
947 } else if (c
->srcFormat
== AV_PIX_FMT_GRAY8
|| c
->srcFormat
== AV_PIX_FMT_GRAY8A
) {
950 av_assert1(c
->srcFormat
== AV_PIX_FMT_BGR4_BYTE
);
951 b
= ( i
>> 3 ) * 255;
952 g
= ((i
>> 1) & 3) * 85;
955 #define RGB2YUV_SHIFT 15
956 #define BY ( (int) (0.114 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
957 #define BV (-(int) (0.081 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
958 #define BU ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
959 #define GY ( (int) (0.587 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
960 #define GV (-(int) (0.419 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
961 #define GU (-(int) (0.331 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
962 #define RY ( (int) (0.299 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
963 #define RV ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
964 #define RU (-(int) (0.169 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
966 y
= av_clip_uint8((RY
* r
+ GY
* g
+ BY
* b
+ ( 33 << (RGB2YUV_SHIFT
- 1))) >> RGB2YUV_SHIFT
);
967 u
= av_clip_uint8((RU
* r
+ GU
* g
+ BU
* b
+ (257 << (RGB2YUV_SHIFT
- 1))) >> RGB2YUV_SHIFT
);
968 v
= av_clip_uint8((RV
* r
+ GV
* g
+ BV
* b
+ (257 << (RGB2YUV_SHIFT
- 1))) >> RGB2YUV_SHIFT
);
969 c
->pal_yuv
[i
]= y
+ (u
<<8) + (v
<<16) + ((unsigned)a
<<24);
971 switch (c
->dstFormat
) {
972 case AV_PIX_FMT_BGR32
:
974 case AV_PIX_FMT_RGB24
:
976 c
->pal_rgb
[i
]= r
+ (g
<<8) + (b
<<16) + ((unsigned)a
<<24);
978 case AV_PIX_FMT_BGR32_1
:
980 case AV_PIX_FMT_BGR24
:
982 c
->pal_rgb
[i
]= a
+ (r
<<8) + (g
<<16) + ((unsigned)b
<<24);
984 case AV_PIX_FMT_RGB32_1
:
986 case AV_PIX_FMT_RGB24
:
988 c
->pal_rgb
[i
]= a
+ (b
<<8) + (g
<<16) + ((unsigned)r
<<24);
990 case AV_PIX_FMT_RGB32
:
992 case AV_PIX_FMT_BGR24
:
995 c
->pal_rgb
[i
]= b
+ (g
<<8) + (r
<<16) + ((unsigned)a
<<24);
1000 if (c
->src0Alpha
&& !c
->dst0Alpha
&& isALPHA(c
->dstFormat
)) {
1003 rgb0_tmp
= av_malloc(FFABS(srcStride
[0]) * srcSliceH
+ 32);
1005 return AVERROR(ENOMEM
);
1007 base
= srcStride
[0] < 0 ? rgb0_tmp
- srcStride
[0] * (srcSliceH
-1) : rgb0_tmp
;
1008 for (y
=0; y
<srcSliceH
; y
++){
1009 memcpy(base
+ srcStride
[0]*y
, src2
[0] + srcStride
[0]*y
, 4*c
->srcW
);
1010 for (x
=c
->src0Alpha
-1; x
<4*c
->srcW
; x
+=4) {
1011 base
[ srcStride
[0]*y
+ x
] = 0xFF;
1017 if (c
->srcXYZ
&& !(c
->dstXYZ
&& c
->srcW
==c
->dstW
&& c
->srcH
==c
->dstH
)) {
1019 rgb0_tmp
= av_malloc(FFABS(srcStride
[0]) * srcSliceH
+ 32);
1021 return AVERROR(ENOMEM
);
1023 base
= srcStride
[0] < 0 ? rgb0_tmp
- srcStride
[0] * (srcSliceH
-1) : rgb0_tmp
;
1025 xyz12Torgb48(c
, (uint16_t*)base
, (const uint16_t*)src2
[0], srcStride
[0]/2, srcSliceH
);
1029 if (!srcSliceY
&& (c
->flags
& SWS_BITEXACT
) && c
->dither
== SWS_DITHER_ED
&& c
->dither_error
[0])
1030 for (i
= 0; i
< 4; i
++)
1031 memset(c
->dither_error
[i
], 0, sizeof(c
->dither_error
[0][0]) * (c
->dstW
+2));
1034 // copy strides, so they can safely be modified
1035 if (c
->sliceDir
== 1) {
1036 // slices go from top to bottom
1037 int srcStride2
[4] = { srcStride
[0], srcStride
[1], srcStride
[2],
1039 int dstStride2
[4] = { dstStride
[0], dstStride
[1], dstStride
[2],
1042 reset_ptr(src2
, c
->srcFormat
);
1043 reset_ptr((void*)dst2
, c
->dstFormat
);
1045 /* reset slice direction at end of frame */
1046 if (srcSliceY
+ srcSliceH
== c
->srcH
)
1049 ret
= c
->swscale(c
, src2
, srcStride2
, srcSliceY
, srcSliceH
, dst2
,
1052 // slices go from bottom to top => we flip the image internally
1053 int srcStride2
[4] = { -srcStride
[0], -srcStride
[1], -srcStride
[2],
1055 int dstStride2
[4] = { -dstStride
[0], -dstStride
[1], -dstStride
[2],
1058 src2
[0] += (srcSliceH
- 1) * srcStride
[0];
1059 if (!usePal(c
->srcFormat
))
1060 src2
[1] += ((srcSliceH
>> c
->chrSrcVSubSample
) - 1) * srcStride
[1];
1061 src2
[2] += ((srcSliceH
>> c
->chrSrcVSubSample
) - 1) * srcStride
[2];
1062 src2
[3] += (srcSliceH
- 1) * srcStride
[3];
1063 dst2
[0] += ( c
->dstH
- 1) * dstStride
[0];
1064 dst2
[1] += ((c
->dstH
>> c
->chrDstVSubSample
) - 1) * dstStride
[1];
1065 dst2
[2] += ((c
->dstH
>> c
->chrDstVSubSample
) - 1) * dstStride
[2];
1066 dst2
[3] += ( c
->dstH
- 1) * dstStride
[3];
1068 reset_ptr(src2
, c
->srcFormat
);
1069 reset_ptr((void*)dst2
, c
->dstFormat
);
1071 /* reset slice direction at end of frame */
1075 ret
= c
->swscale(c
, src2
, srcStride2
, c
->srcH
-srcSliceY
-srcSliceH
,
1076 srcSliceH
, dst2
, dstStride2
);
1080 if (c
->dstXYZ
&& !(c
->srcXYZ
&& c
->srcW
==c
->dstW
&& c
->srcH
==c
->dstH
)) {
1081 /* replace on the same data */
1082 rgb48Toxyz12(c
, (uint16_t*)dst2
[0], (const uint16_t*)dst2
[0], dstStride
[0]/2, ret
);