1 /*
2 * Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at>
3 *
4 * This file is part of FFmpeg.
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <string.h>
24
33 #include "config.h"
36
38 { 36, 68, 60, 92, 34, 66, 58, 90, },
39 { 100, 4, 124, 28, 98, 2, 122, 26, },
40 { 52, 84, 44, 76, 50, 82, 42, 74, },
41 { 116, 20, 108, 12, 114, 18, 106, 10, },
42 { 32, 64, 56, 88, 38, 70, 62, 94, },
43 { 96, 0, 120, 24, 102, 6, 126, 30, },
44 { 48, 80, 40, 72, 54, 86, 46, 78, },
45 { 112, 16, 104, 8, 118, 22, 110, 14, },
46 { 36, 68, 60, 92, 34, 66, 58, 90, },
47 };
48
50 64, 64, 64, 64, 64, 64, 64, 64
51 };
52
55 {
57 uint8_t *ptr = plane +
stride * y;
61 }
62 }
63
65 const uint8_t *_src,
const int16_t *
filter,
66 const int32_t *filterPos,
int filterSize)
67 {
71 const uint16_t *
src = (
const uint16_t *) _src;
74
76 sh = 9;
78 sh = 16 - 1 - 4;
79 }
80
81 for (
i = 0;
i < dstW;
i++) {
82 int j;
83 int srcPos = filterPos[
i];
85
86 for (j = 0; j < filterSize; j++) {
88 }
89 // filter=14 bit, input=16 bit, output=30 bit, >> 11 makes 19 bit
91 }
92 }
93
95 const uint8_t *_src,
const int16_t *
filter,
96 const int32_t *filterPos,
int filterSize)
97 {
100 const uint16_t *
src = (
const uint16_t *) _src;
101 int sh =
desc->comp[0].depth - 1;
102
103 if (sh<15) {
106 sh = 16 - 1;
107 }
108
109 for (
i = 0;
i < dstW;
i++) {
110 int j;
111 int srcPos = filterPos[
i];
113
114 for (j = 0; j < filterSize; j++) {
116 }
117 // filter=14 bit, input=16 bit, output=30 bit, >> 15 makes 15 bit
118 dst[
i] =
FFMIN(
val >> sh, (1 << 15) - 1);
119 }
120 }
121
122 // bilinear / bicubic scaling
124 const uint8_t *
src,
const int16_t *
filter,
125 const int32_t *filterPos,
int filterSize)
126 {
128 for (
i = 0;
i < dstW;
i++) {
129 int j;
130 int srcPos = filterPos[
i];
132 for (j = 0; j < filterSize; j++) {
134 }
135 dst[
i] =
FFMIN(
val >> 7, (1 << 15) - 1);
// the cubic equation does overflow ...
136 }
137 }
138
140 const uint8_t *
src,
const int16_t *
filter,
141 const int32_t *filterPos,
int filterSize)
142 {
145 for (
i = 0;
i < dstW;
i++) {
146 int j;
147 int srcPos = filterPos[
i];
149 for (j = 0; j < filterSize; j++) {
151 }
152 dst[
i] =
FFMIN(
val >> 3, (1 << 19) - 1);
// the cubic equation does overflow ...
153 }
154 }
155
156 // FIXME all pal and rgb srcFormats could do this conversion as well
157 // FIXME all scalers more complex than bilinear could do half of this transform
159 {
162 dstU[
i] = (
FFMIN(dstU[
i], 30775) * 4663 - 9289992) >> 12;
// -264
163 dstV[
i] = (
FFMIN(dstV[
i], 30775) * 4663 - 9289992) >> 12;
// -264
164 }
165 }
166
168 {
171 dstU[
i] = (dstU[
i] * 1799 + 4081085) >> 11;
// 1469
172 dstV[
i] = (dstV[
i] * 1799 + 4081085) >> 11;
// 1469
173 }
174 }
175
177 {
180 dst[
i] = (
FFMIN(dst[
i], 30189) * 19077 - 39057361) >> 14;
181 }
182
184 {
187 dst[
i] = (dst[
i] * 14071 + 33561947) >> 14;
188 }
189
191 {
196 dstU[
i] = (
FFMIN(dstU[
i], 30775 << 4) * 4663 - (9289992 << 4)) >> 12;
// -264
197 dstV[
i] = (
FFMIN(dstV[
i], 30775 << 4) * 4663 - (9289992 << 4)) >> 12;
// -264
198 }
199 }
200
202 {
207 dstU[
i] = (dstU[
i] * 1799 + (4081085 << 4)) >> 11;
// 1469
208 dstV[
i] = (dstV[
i] * 1799 + (4081085 << 4)) >> 11;
// 1469
209 }
210 }
211
213 {
217 dst[
i] = ((
int)(
FFMIN(dst[
i], 30189 << 4) * 4769
U - (39057361 << 2))) >> 12;
218 }
219 }
220
222 {
226 dst[
i] = (dst[
i]*(14071/4) + (33561947<<4)/4)>>12;
227 }
228
229
230 #define DEBUG_SWSCALE_BUFFERS 0
231 #define DEBUG_BUFFERS(...) \
232 if (DEBUG_SWSCALE_BUFFERS) \
233 av_log(c, AV_LOG_DEBUG, __VA_ARGS__)
234
236 int srcStride[],
int srcSliceY,
int srcSliceH,
237 uint8_t *dst[], int dstStride[],
238 int dstSliceY, int dstSliceH)
239 {
240 const int scale_dst = dstSliceY > 0 || dstSliceH <
c->dstH;
241
242 /* load a few things into local vars to make the code more readable?
243 * and faster */
244 const int dstW =
c->dstW;
246
248 const int flags =
c->flags;
249 int32_t *vLumFilterPos =
c->vLumFilterPos;
250 int32_t *vChrFilterPos =
c->vChrFilterPos;
251
252 const int vLumFilterSize =
c->vLumFilterSize;
253 const int vChrFilterSize =
c->vChrFilterSize;
254
262 const int chrSrcSliceY = srcSliceY >>
c->chrSrcVSubSample;
264 int should_dither =
isNBPS(
c->srcFormat) ||
266 int lastDstY;
267
268 /* vars which will change and which we need to store back in the context */
270 int lastInLumBuf =
c->lastInLumBuf;
271 int lastInChrBuf =
c->lastInChrBuf;
272
273 int lumStart = 0;
274 int lumEnd =
c->descIndex[0];
275 int chrStart = lumEnd;
276 int chrEnd =
c->descIndex[1];
277 int vStart = chrEnd;
278 int vEnd =
c->numDesc;
279 SwsSlice *src_slice = &
c->slice[lumStart];
280 SwsSlice *hout_slice = &
c->slice[
c->numSlice-2];
281 SwsSlice *vout_slice = &
c->slice[
c->numSlice-1];
283
284 int needAlpha =
c->needAlpha;
285
286 int hasLumHoles = 1;
287 int hasChrHoles = 1;
288
293 srcStride[1] =
294 srcStride[2] =
295 srcStride[3] = srcStride[0];
296 }
297 srcStride[1] *= 1 <<
c->vChrDrop;
298 srcStride[2] *= 1 <<
c->vChrDrop;
299
300 DEBUG_BUFFERS(
"swscale() %p[%d] %p[%d] %p[%d] %p[%d] -> %p[%d] %p[%d] %p[%d] %p[%d]\n",
301 src[0], srcStride[0],
src[1], srcStride[1],
302 src[2], srcStride[2],
src[3], srcStride[3],
303 dst[0], dstStride[0], dst[1], dstStride[1],
304 dst[2], dstStride[2], dst[3], dstStride[3]);
305 DEBUG_BUFFERS(
"srcSliceY: %d srcSliceH: %d dstY: %d dstH: %d\n",
308 vLumFilterSize, vChrFilterSize);
309
310 if (dstStride[0]&15 || dstStride[1]&15 ||
311 dstStride[2]&15 || dstStride[3]&15) {
316 "Warning: dstStride is not aligned!\n"
317 " ->cannot do aligned memory accesses anymore\n");
318 }
319 }
320
321 #if ARCH_X86
322 if ( (uintptr_t)dst[0]&15 || (uintptr_t)dst[1]&15 || (uintptr_t)dst[2]&15
323 || (uintptr_t)
src[0]&15 || (uintptr_t)
src[1]&15 || (uintptr_t)
src[2]&15
324 || dstStride[0]&15 || dstStride[1]&15 || dstStride[2]&15 || dstStride[3]&15
325 || srcStride[0]&15 || srcStride[1]&15 || srcStride[2]&15 || srcStride[3]&15
326 ) {
332 }
333 }
334 #endif
335
336 if (scale_dst) {
337 dstY = dstSliceY;
338 dstH = dstY + dstSliceH;
339 lastInLumBuf = -1;
340 lastInChrBuf = -1;
341 } else if (srcSliceY == 0) {
342 /* Note the user might start scaling the picture in the middle so this
343 * will not get executed. This is not really intended but works
344 * currently, so people might do it. */
345 dstY = 0;
346 lastInLumBuf = -1;
347 lastInChrBuf = -1;
348 }
349
350 if (!should_dither) {
352 }
353 lastDstY = dstY;
354
356 yuv2packed1, yuv2packed2, yuv2packedX, yuv2anyX,
c->use_mmx_vfilter);
357
359 srcSliceY,
srcSliceH, chrSrcSliceY, chrSrcSliceH, 1);
360
362 dstY, dstSliceH, dstY >>
c->chrDstVSubSample,
364 if (srcSliceY == 0) {
369
374 hout_slice->
width = dstW;
375 }
376
377 for (; dstY < dstH; dstY++) {
378 const int chrDstY = dstY >>
c->chrDstVSubSample;
379 int use_mmx_vfilter=
c->use_mmx_vfilter;
380
381 // First line needed as input
382 const int firstLumSrcY =
FFMAX(1 - vLumFilterSize, vLumFilterPos[dstY]);
383 const int firstLumSrcY2 =
FFMAX(1 - vLumFilterSize, vLumFilterPos[
FFMIN(dstY | ((1 <<
c->chrDstVSubSample) - 1),
c->dstH - 1)]);
384 // First line needed as input
385 const int firstChrSrcY =
FFMAX(1 - vChrFilterSize, vChrFilterPos[chrDstY]);
386
387 // Last line needed as input
388 int lastLumSrcY =
FFMIN(
c->srcH, firstLumSrcY + vLumFilterSize) - 1;
389 int lastLumSrcY2 =
FFMIN(
c->srcH, firstLumSrcY2 + vLumFilterSize) - 1;
390 int lastChrSrcY =
FFMIN(
c->chrSrcH, firstChrSrcY + vChrFilterSize) - 1;
391 int enough_lines;
392
394 int posY, cPosY, firstPosY, lastPosY, firstCPosY, lastCPosY;
395
396 // handle holes (FAST_BILINEAR & weird filters)
397 if (firstLumSrcY > lastInLumBuf) {
398
399 hasLumHoles = lastInLumBuf != firstLumSrcY - 1;
400 if (hasLumHoles) {
405 }
406
407 lastInLumBuf = firstLumSrcY - 1;
408 }
409 if (firstChrSrcY > lastInChrBuf) {
410
411 hasChrHoles = lastInChrBuf != firstChrSrcY - 1;
412 if (hasChrHoles) {
417 }
418
419 lastInChrBuf = firstChrSrcY - 1;
420 }
421
423 DEBUG_BUFFERS(
"\tfirstLumSrcY: %d lastLumSrcY: %d lastInLumBuf: %d\n",
424 firstLumSrcY, lastLumSrcY, lastInLumBuf);
425 DEBUG_BUFFERS(
"\tfirstChrSrcY: %d lastChrSrcY: %d lastInChrBuf: %d\n",
426 firstChrSrcY, lastChrSrcY, lastInChrBuf);
427
428 // Do we have enough lines in this slice to output the dstY line
429 enough_lines = lastLumSrcY2 < srcSliceY +
srcSliceH &&
431
432 if (!enough_lines) {
434 lastChrSrcY = chrSrcSliceY + chrSrcSliceH - 1;
435 DEBUG_BUFFERS(
"buffering slice: lastLumSrcY %d lastChrSrcY %d\n",
436 lastLumSrcY, lastChrSrcY);
437 }
438
441
442
444 if (posY <= lastLumSrcY && !hasLumHoles) {
445 firstPosY =
FFMAX(firstLumSrcY, posY);
447 } else {
448 firstPosY = posY;
449 lastPosY = lastLumSrcY;
450 }
451
453 if (cPosY <= lastChrSrcY && !hasChrHoles) {
454 firstCPosY =
FFMAX(firstChrSrcY, cPosY);
456 } else {
457 firstCPosY = cPosY;
458 lastCPosY = lastChrSrcY;
459 }
460
462
463 if (posY < lastLumSrcY + 1) {
464 for (
i = lumStart;
i < lumEnd; ++
i)
466 }
467
468 lastInLumBuf = lastLumSrcY;
469
470 if (cPosY < lastChrSrcY + 1) {
471 for (
i = chrStart;
i < chrEnd; ++
i)
473 }
474
475 lastInChrBuf = lastChrSrcY;
476
477 if (!enough_lines)
478 break; // we can't output a dstY line so let's try with the next slice
479
480 #if HAVE_MMX_INLINE
482 #endif
483 if (should_dither) {
486 }
487 if (dstY >=
c->dstH - 2) {
488 /* hmm looks like we can't use MMX here without overwriting
489 * this array's tail */
491 &yuv2packed1, &yuv2packed2, &yuv2packedX, &yuv2anyX);
492 use_mmx_vfilter= 0;
494 yuv2packed1, yuv2packed2, yuv2packedX, yuv2anyX, use_mmx_vfilter);
495 }
496
497 for (
i = vStart;
i < vEnd; ++
i)
499 }
501 int offset = lastDstY - dstSliceY;
502 int length = dstW;
503 int height = dstY - lastDstY;
504
508 1,
desc->comp[3].depth,
510 }
else if (
is32BPS(dstFormat)) {
513 1,
desc->comp[3].depth,
515 } else
517 }
518
519 #if HAVE_MMXEXT_INLINE
521 __asm__ volatile (
"sfence" :::
"memory");
522 #endif
524
525 /* store changed local vars back in the context */
527 c->lastInLumBuf = lastInLumBuf;
528 c->lastInChrBuf = lastInChrBuf;
529
530 return dstY - lastDstY;
531 }
532
534 {
535 c->lumConvertRange =
NULL;
536 c->chrConvertRange =
NULL;
537 if (
c->srcRange !=
c->dstRange && !
isAnyRGB(
c->dstFormat)) {
538 if (
c->dstBpc <= 14) {
542 } else {
545 }
546 } else {
550 } else {
553 }
554 }
555 }
556 }
557
559 {
561
563 &
c->yuv2nv12cX, &
c->yuv2packed1,
564 &
c->yuv2packed2, &
c->yuv2packedX, &
c->yuv2anyX);
565
567
568 if (
c->srcBpc == 8) {
569 if (
c->dstBpc <= 14) {
574 }
575 } else {
577 }
578 } else {
581 }
582
584
587 c->needs_hcscale = 1;
588 }
589
591 {
593
594 #if ARCH_PPC
596 #elif ARCH_X86
598 #elif ARCH_AARCH64
600 #elif ARCH_ARM
602 #elif ARCH_LOONGARCH64
604 #endif
605 }
606
608 {
613
616 }
617 }
618
620 const int linesizes[4])
621 {
624
626
627 for (
i = 0;
i < 4;
i++) {
628 int plane =
desc->comp[
i].plane;
629 if (!
data[plane] || !linesizes[plane])
630 return 0;
631 }
632
633 return 1;
634 }
635
638 {
639 int xp,yp;
641
642 for (yp=0; yp<
h; yp++) {
643 for (xp=0; xp+2<
stride; xp+=3) {
644 int x, y, z,
r,
g,
b;
645
650 } else {
654 }
655
656 x =
c->xyzgamma[x>>4];
657 y =
c->xyzgamma[y>>4];
658 z =
c->xyzgamma[z>>4];
659
660 // convert from XYZlinear to sRGBlinear
661 r =
c->xyz2rgb_matrix[0][0] * x +
662 c->xyz2rgb_matrix[0][1] * y +
663 c->xyz2rgb_matrix[0][2] * z >> 12;
664 g =
c->xyz2rgb_matrix[1][0] * x +
665 c->xyz2rgb_matrix[1][1] * y +
666 c->xyz2rgb_matrix[1][2] * z >> 12;
667 b =
c->xyz2rgb_matrix[2][0] * x +
668 c->xyz2rgb_matrix[2][1] * y +
669 c->xyz2rgb_matrix[2][2] * z >> 12;
670
671 // limit values to 12-bit depth
675
676 // convert from sRGBlinear to RGB and scale from 12bit to 16bit
678 AV_WB16(dst + xp + 0,
c->rgbgamma[
r] << 4);
679 AV_WB16(dst + xp + 1,
c->rgbgamma[
g] << 4);
680 AV_WB16(dst + xp + 2,
c->rgbgamma[
b] << 4);
681 } else {
682 AV_WL16(dst + xp + 0,
c->rgbgamma[
r] << 4);
683 AV_WL16(dst + xp + 1,
c->rgbgamma[
g] << 4);
684 AV_WL16(dst + xp + 2,
c->rgbgamma[
b] << 4);
685 }
686 }
689 }
690 }
691
694 {
695 int xp,yp;
697
698 for (yp=0; yp<
h; yp++) {
699 for (xp=0; xp+2<
stride; xp+=3) {
700 int x, y, z,
r,
g,
b;
701
706 } else {
710 }
711
712 r =
c->rgbgammainv[
r>>4];
713 g =
c->rgbgammainv[
g>>4];
714 b =
c->rgbgammainv[
b>>4];
715
716 // convert from sRGBlinear to XYZlinear
717 x =
c->rgb2xyz_matrix[0][0] *
r +
718 c->rgb2xyz_matrix[0][1] *
g +
719 c->rgb2xyz_matrix[0][2] *
b >> 12;
720 y =
c->rgb2xyz_matrix[1][0] *
r +
721 c->rgb2xyz_matrix[1][1] *
g +
722 c->rgb2xyz_matrix[1][2] *
b >> 12;
723 z =
c->rgb2xyz_matrix[2][0] *
r +
724 c->rgb2xyz_matrix[2][1] *
g +
725 c->rgb2xyz_matrix[2][2] *
b >> 12;
726
727 // limit values to 12-bit depth
731
732 // convert from XYZlinear to X'Y'Z' and scale from 12bit to 16bit
734 AV_WB16(dst + xp + 0,
c->xyzgammainv[x] << 4);
735 AV_WB16(dst + xp + 1,
c->xyzgammainv[y] << 4);
736 AV_WB16(dst + xp + 2,
c->xyzgammainv[z] << 4);
737 } else {
738 AV_WL16(dst + xp + 0,
c->xyzgammainv[x] << 4);
739 AV_WL16(dst + xp + 1,
c->xyzgammainv[y] << 4);
740 AV_WL16(dst + xp + 2,
c->xyzgammainv[z] << 4);
741 }
742 }
745 }
746 }
747
749 {
750 for (
int i = 0;
i < 256;
i++) {
751 int r,
g,
b, y,
u, v,
a = 0xff;
754 a = (p >> 24) & 0xFF;
755 r = (p >> 16) & 0xFF;
760 g = ((
i >> 2) & 7) * 36;
764 g = ((
i >> 3) & 7) * 36;
767 r = (
i >> 3 ) * 255;
768 g = ((
i >> 1) & 3) * 85;
772 } else {
774 b = (
i >> 3 ) * 255;
775 g = ((
i >> 1) & 3) * 85;
777 }
778 #define RGB2YUV_SHIFT 15
779 #define BY ( (int) (0.114 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
780 #define BV (-(int) (0.081 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
781 #define BU ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
782 #define GY ( (int) (0.587 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
783 #define GV (-(int) (0.419 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
784 #define GU (-(int) (0.331 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
785 #define RY ( (int) (0.299 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
786 #define RV ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
787 #define RU (-(int) (0.169 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
788
792 c->pal_yuv[
i]= y + (
u<<8) + (v<<16) + ((unsigned)
a<<24);
793
794 switch (
c->dstFormat) {
796 #if !HAVE_BIGENDIAN
798 #endif
799 c->pal_rgb[
i]=
r + (
g<<8) + (
b<<16) + ((unsigned)
a<<24);
800 break;
802 #if HAVE_BIGENDIAN
804 #endif
805 c->pal_rgb[
i]=
a + (
r<<8) + (
g<<16) + ((unsigned)
b<<24);
806 break;
808 #if HAVE_BIGENDIAN
810 #endif
811 c->pal_rgb[
i]=
a + (
b<<8) + (
g<<16) + ((unsigned)
r<<24);
812 break;
814 #if !HAVE_BIGENDIAN
816 #endif
817 default:
818 c->pal_rgb[
i]=
b + (
g<<8) + (
r<<16) + ((unsigned)
a<<24);
819 }
820 }
821 }
822
824 const uint8_t * const srcSlice[], const int srcStride[],
826 uint8_t *const dstSlice[], const int dstStride[],
827 int dstSliceY, int dstSliceH);
828
830 const uint8_t * const srcSlice[], const int srcStride[],
832 uint8_t * const dstSlice[], const int dstStride[],
833 int dstSliceY, int dstSliceH)
834 {
836 srcSlice, srcStride, srcSliceY,
srcSliceH,
837 c->cascaded_tmp,
c->cascaded_tmpStride, 0,
c->srcH);
838
841
842 if (
c->cascaded_context[2])
845 c->cascaded1_tmp,
c->cascaded1_tmpStride, 0,
c->dstH);
846 else
849 dstSlice, dstStride, dstSliceY, dstSliceH);
850
853
854 if (
c->cascaded_context[2]) {
856 c->cascaded1_tmpStride,
c->cascaded_context[1]->dstY -
ret,
857 c->cascaded_context[1]->dstY,
858 dstSlice, dstStride, dstSliceY, dstSliceH);
859 }
861 }
862
864 const uint8_t * const srcSlice[], const int srcStride[],
866 uint8_t * const dstSlice[], const int dstStride[],
867 int dstSliceY, int dstSliceH)
868 {
870 srcSlice, srcStride, srcSliceY,
srcSliceH,
871 c->cascaded_tmp,
c->cascaded_tmpStride,
872 0,
c->cascaded_context[0]->dstH);
876 (
const uint8_t *
const * )
c->cascaded_tmp,
c->cascaded_tmpStride,
877 0,
c->cascaded_context[0]->dstH,
878 dstSlice, dstStride, dstSliceY, dstSliceH);
880 }
881
883 const uint8_t * const srcSlice[], const int srcStride[],
885 uint8_t *const dstSlice[], const int dstStride[],
886 int dstSliceY, int dstSliceH)
887 {
888 const int scale_dst = dstSliceY > 0 || dstSliceH <
c->dstH;
891 const uint8_t *
src2[4];
892 uint8_t *dst2[4];
893 int macro_height_src =
isBayer(
c->srcFormat) ? 2 : (1 <<
c->chrSrcVSubSample);
894 int macro_height_dst =
isBayer(
c->dstFormat) ? 2 : (1 <<
c->chrDstVSubSample);
895 // copy strides, so they can safely be modified
896 int srcStride2[4];
897 int dstStride2[4];
898 int srcSliceY_internal = srcSliceY;
899
900 if (!srcStride || !dstStride || !dstSlice || !srcSlice) {
901 av_log(
c,
AV_LOG_ERROR,
"One of the input parameters to sws_scale() is NULL, please check the calling code\n");
903 }
904
905 if ((srcSliceY & (macro_height_src - 1)) ||
911 }
912
913 if ((dstSliceY & (macro_height_dst - 1)) ||
914 ((dstSliceH & (macro_height_dst - 1)) && dstSliceY + dstSliceH !=
c->dstH) ||
915 dstSliceY + dstSliceH >
c->dstH) {
918 }
919
923 }
927 }
928
929 // do not mess up sliceDir if we have a "trailing" 0-size slice
931 return 0;
932
933 if (
c->gamma_flag &&
c->cascaded_context[0])
935 dstSlice, dstStride, dstSliceY, dstSliceH);
936
937 if (
c->cascaded_context[0] && srcSliceY == 0 &&
srcSliceH ==
c->cascaded_context[0]->srcH)
939 dstSlice, dstStride, dstSliceY, dstSliceH);
940
942 for (
i = 0;
i < 4;
i++)
943 memset(
c->dither_error[
i], 0,
sizeof(
c->dither_error[0][0]) * (
c->dstW+2));
944
947
948 memcpy(
src2, srcSlice,
sizeof(
src2));
949 memcpy(dst2, dstSlice, sizeof(dst2));
950 memcpy(srcStride2, srcStride, sizeof(srcStride2));
951 memcpy(dstStride2, dstStride, sizeof(dstStride2));
952
954 if (srcSliceY != 0 && srcSliceY +
srcSliceH !=
c->srcH) {
957 }
958
959 c->sliceDir = (srcSliceY == 0) ? 1 : -1;
960 } else if (scale_dst)
962
963 if (
c->src0Alpha && !
c->dst0Alpha &&
isALPHA(
c->dstFormat)) {
965 int x,y;
966
969 if (!
c->rgb0_scratch)
971
972 base = srcStride[0] < 0 ?
c->rgb0_scratch - srcStride[0] * (
srcSliceH-1) :
975 memcpy(
base + srcStride[0]*y,
src2[0] + srcStride[0]*y, 4*
c->srcW);
976 for (x=
c->src0Alpha-1; x<4*c->srcW; x+=4) {
977 base[ srcStride[0]*y + x] = 0xFF;
978 }
979 }
981 }
982
983 if (
c->srcXYZ && !(
c->dstXYZ &&
c->srcW==
c->dstW &&
c->srcH==
c->dstH)) {
985
990
991 base = srcStride[0] < 0 ?
c->xyz_scratch - srcStride[0] * (
srcSliceH-1) :
993
996 }
997
998 if (
c->sliceDir != 1) {
999 // slices go from bottom to top => we flip the image internally
1000 for (
i=0;
i<4;
i++) {
1001 srcStride2[
i] *= -1;
1002 dstStride2[
i] *= -1;
1003 }
1004
1007 src2[1] += ((
srcSliceH >>
c->chrSrcVSubSample) - 1) * srcStride[1];
1008 src2[2] += ((
srcSliceH >>
c->chrSrcVSubSample) - 1) * srcStride[2];
1010 dst2[0] += (
c->dstH - 1) * dstStride[0];
1011 dst2[1] += ((
c->dstH >>
c->chrDstVSubSample) - 1) * dstStride[1];
1012 dst2[2] += ((
c->dstH >>
c->chrDstVSubSample) - 1) * dstStride[2];
1013 dst2[3] += (
c->dstH - 1) * dstStride[3];
1014
1015 srcSliceY_internal =
c->srcH-srcSliceY-
srcSliceH;
1016 }
1019
1020 if (
c->convert_unscaled) {
1021 int offset = srcSliceY_internal;
1023
1024 // for dst slice scaling, offset the pointers to match the unscaled API
1025 if (scale_dst) {
1027 for (
i = 0;
i < 4 &&
src2[
i];
i++) {
1029 break;
1030 src2[
i] += (dstSliceY >> ((
i == 1 ||
i == 2) ?
c->chrSrcVSubSample : 0)) * srcStride2[
i];
1031 }
1032
1033 for (
i = 0;
i < 4 && dst2[
i];
i++) {
1034 if (!dst2[
i] || (
i > 0 &&
usePal(
c->dstFormat)))
1035 break;
1036 dst2[
i] -= (dstSliceY >> ((
i == 1 ||
i == 2) ?
c->chrDstVSubSample : 0)) * dstStride2[
i];
1037 }
1039 slice_h = dstSliceH;
1040 }
1041
1043 dst2, dstStride2);
1044 if (scale_dst)
1045 dst2[0] += dstSliceY * dstStride2[0];
1046 } else {
1048 dst2, dstStride2, dstSliceY, dstSliceH);
1049 }
1050
1051 if (
c->dstXYZ && !(
c->srcXYZ &&
c->srcW==
c->dstW &&
c->srcH==
c->dstH)) {
1052 uint16_t *dst16;
1053
1054 if (scale_dst) {
1055 dst16 = (uint16_t *)dst2[0];
1056 } else {
1057 int dstY =
c->dstY ?
c->dstY : srcSliceY +
srcSliceH;
1058
1062 dst16 = (uint16_t*)(dst2[0] + (dstY -
ret) * dstStride2[0]);
1063 }
1064
1065 /* replace on the same data */
1067 }
1068
1069 /* reset slice direction at end of frame */
1070 if ((srcSliceY_internal +
srcSliceH ==
c->srcH) || scale_dst)
1072
1074 }
1075
1077 {
1080 c->src_ranges.nb_ranges = 0;
1081 }
1082
1084 {
1085 int ret, allocated = 0;
1086
1090
1095
1099 allocated = 1;
1100 }
1101
1104 if (allocated)
1106
1108 }
1109
1110 return 0;
1111 }
1112
1114 unsigned int slice_height)
1115 {
1117
1121
1122 return 0;
1123 }
1124
1126 {
1128 return c->slice_ctx[0]->dst_slice_align;
1129
1130 return c->dst_slice_align;
1131 }
1132
1134 unsigned int slice_height)
1135 {
1137 uint8_t *dst[4];
1138
1139 /* wait until complete input has been received */
1140 if (!(
c->src_ranges.nb_ranges == 1 &&
1141 c->src_ranges.ranges[0].start == 0 &&
1142 c->src_ranges.ranges[0].len ==
c->srcH))
1144
1145 if ((
slice_start > 0 || slice_height < c->dstH) &&
1148 "Incorrectly aligned output: %u/%u not multiples of %u\n",
1151 }
1152
1153 if (
c->slicethread) {
1154 int nb_jobs =
c->slice_ctx[0]->dither ==
SWS_DITHER_ED ? 1 :
c->nb_slice_ctx;
1156
1158 c->dst_slice_height = slice_height;
1159
1161
1162 for (
int i = 0;
i <
c->nb_slice_ctx;
i++) {
1163 if (
c->slice_err[
i] < 0) {
1164 ret =
c->slice_err[
i];
1165 break;
1166 }
1167 }
1168
1169 memset(
c->slice_err, 0,
c->nb_slice_ctx *
sizeof(*
c->slice_err));
1170
1172 }
1173
1175 ptrdiff_t
offset =
c->frame_dst->linesize[
i] * (ptrdiff_t)(
slice_start >>
c->chrDstVSubSample);
1177 }
1178
1180 c->frame_src->linesize, 0,
c->srcH,
1181 dst,
c->frame_dst->linesize,
slice_start, slice_height);
1182 }
1183
1185 {
1187
1191
1195
1197
1199 }
1200
1201 /**
1202 * swscale wrapper, so we don't need to export the SwsContext.
1203 * Assumes planar YUV to be in YUV order instead of YVU.
1204 */
1206 const uint8_t * const srcSlice[],
1207 const int srcStride[], int srcSliceY,
1209 const int dstStride[])
1210 {
1211 if (
c->nb_slice_ctx)
1212 c =
c->slice_ctx[0];
1213
1215 dst, dstStride, 0,
c->dstH);
1216 }
1217
1219 int nb_jobs, int nb_threads)
1220 {
1223
1225 c->dst_slice_align);
1228 int err = 0;
1229
1231 uint8_t *dst[4] = {
NULL };
1232
1234 const int vshift = (
i == 1 ||
i == 2) ?
c->chrDstVSubSample : 0;
1237
1239 }
1240
1245 }
1246
1248 }