FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/swscale.c
Date: 2025-04-25 22:50:00
Exec Total Coverage
Lines: 576 837 68.8%
Functions: 30 39 76.9%
Branches: 308 585 52.6%

Line Branch Exec Source
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
25 #include "libavutil/avassert.h"
26 #include "libavutil/bswap.h"
27 #include "libavutil/common.h"
28 #include "libavutil/cpu.h"
29 #include "libavutil/emms.h"
30 #include "libavutil/intreadwrite.h"
31 #include "libavutil/mem.h"
32 #include "libavutil/mem_internal.h"
33 #include "libavutil/pixdesc.h"
34 #include "config.h"
35 #include "swscale_internal.h"
36 #include "swscale.h"
37
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, },
48 };
49
50 DECLARE_ALIGNED(8, static const uint8_t, sws_pb_64)[8] = {
51 64, 64, 64, 64, 64, 64, 64, 64
52 };
53
54 5566 static av_always_inline void fillPlane(uint8_t *plane, int stride, int width,
55 int height, int y, uint8_t val)
56 {
57 int i;
58 5566 uint8_t *ptr = plane + stride * y;
59
2/2
✓ Branch 0 taken 140692 times.
✓ Branch 1 taken 5566 times.
146258 for (i = 0; i < height; i++) {
60 140692 memset(ptr, val, width);
61 140692 ptr += stride;
62 }
63 5566 }
64
65 6956095 static void hScale16To19_c(SwsInternal *c, int16_t *_dst, int dstW,
66 const uint8_t *_src, const int16_t *filter,
67 const int32_t *filterPos, int filterSize)
68 {
69 6956095 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
70 int i;
71 6956095 int32_t *dst = (int32_t *) _dst;
72 6956095 const uint16_t *src = (const uint16_t *) _src;
73 6956095 int bits = desc->comp[0].depth - 1;
74 6956095 int sh = bits - 4;
75
76
5/6
✓ Branch 1 taken 4038890 times.
✓ Branch 2 taken 2917205 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4038890 times.
✓ Branch 5 taken 2015038 times.
✓ Branch 6 taken 902167 times.
6956095 if ((isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8) && desc->comp[0].depth<16) {
77 2015038 sh = 9;
78
2/2
✓ Branch 0 taken 27613 times.
✓ Branch 1 taken 4913444 times.
4941057 } else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
79 27613 sh = 16 - 1 - 4;
80 }
81
82
2/2
✓ Branch 0 taken 2080162107 times.
✓ Branch 1 taken 6956095 times.
2087118202 for (i = 0; i < dstW; i++) {
83 int j;
84 2080162107 int srcPos = filterPos[i];
85 2080162107 int val = 0;
86
87
2/2
✓ Branch 0 taken 3929294907 times.
✓ Branch 1 taken 2080162107 times.
6009457014 for (j = 0; j < filterSize; j++) {
88 3929294907 val += src[srcPos + j] * filter[filterSize * i + j];
89 }
90 // filter=14 bit, input=16 bit, output=30 bit, >> 11 makes 19 bit
91 2080162107 dst[i] = FFMIN(val >> sh, (1 << 19) - 1);
92 }
93 6956095 }
94
95 35183596 static void hScale16To15_c(SwsInternal *c, int16_t *dst, int dstW,
96 const uint8_t *_src, const int16_t *filter,
97 const int32_t *filterPos, int filterSize)
98 {
99 35183596 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
100 int i;
101 35183596 const uint16_t *src = (const uint16_t *) _src;
102 35183596 int sh = desc->comp[0].depth - 1;
103
104
2/2
✓ Branch 0 taken 28810676 times.
✓ Branch 1 taken 6372920 times.
35183596 if (sh<15) {
105
4/4
✓ Branch 1 taken 16154457 times.
✓ Branch 2 taken 12656219 times.
✓ Branch 3 taken 15614473 times.
✓ Branch 4 taken 539984 times.
28810676 sh = isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8 ? 13 : (desc->comp[0].depth - 1);
106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6372920 times.
6372920 } else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
107 sh = 16 - 1;
108 }
109
110
2/2
✓ Branch 0 taken 10750740429 times.
✓ Branch 1 taken 35183596 times.
10785924025 for (i = 0; i < dstW; i++) {
111 int j;
112 10750740429 int srcPos = filterPos[i];
113 10750740429 int val = 0;
114
115
2/2
✓ Branch 0 taken 20094339341 times.
✓ Branch 1 taken 10750740429 times.
30845079770 for (j = 0; j < filterSize; j++) {
116 20094339341 val += src[srcPos + j] * filter[filterSize * i + j];
117 }
118 // filter=14 bit, input=16 bit, output=30 bit, >> 15 makes 15 bit
119 10750740429 dst[i] = FFMIN(val >> sh, (1 << 15) - 1);
120 }
121 35183596 }
122
123 // bilinear / bicubic scaling
124 20984797 static void hScale8To15_c(SwsInternal *c, int16_t *dst, int dstW,
125 const uint8_t *src, const int16_t *filter,
126 const int32_t *filterPos, int filterSize)
127 {
128 int i;
129
2/2
✓ Branch 0 taken 6359650892 times.
✓ Branch 1 taken 20984797 times.
6380635689 for (i = 0; i < dstW; i++) {
130 int j;
131 6359650892 int srcPos = filterPos[i];
132 6359650892 int val = 0;
133
2/2
✓ Branch 0 taken 16211901714 times.
✓ Branch 1 taken 6359650892 times.
22571552606 for (j = 0; j < filterSize; j++) {
134 16211901714 val += ((int)src[srcPos + j]) * filter[filterSize * i + j];
135 }
136 6359650892 dst[i] = FFMIN(val >> 7, (1 << 15) - 1); // the cubic equation does overflow ...
137 }
138 20984797 }
139
140 2332121 static void hScale8To19_c(SwsInternal *c, int16_t *_dst, int dstW,
141 const uint8_t *src, const int16_t *filter,
142 const int32_t *filterPos, int filterSize)
143 {
144 int i;
145 2332121 int32_t *dst = (int32_t *) _dst;
146
2/2
✓ Branch 0 taken 700586780 times.
✓ Branch 1 taken 2332121 times.
702918901 for (i = 0; i < dstW; i++) {
147 int j;
148 700586780 int srcPos = filterPos[i];
149 700586780 int val = 0;
150
2/2
✓ Branch 0 taken 1372727148 times.
✓ Branch 1 taken 700586780 times.
2073313928 for (j = 0; j < filterSize; j++) {
151 1372727148 val += ((int)src[srcPos + j]) * filter[filterSize * i + j];
152 }
153 700586780 dst[i] = FFMIN(val >> 3, (1 << 19) - 1); // the cubic equation does overflow ...
154 }
155 2332121 }
156
157 // FIXME all pal and rgb srcFormats could do this conversion as well
158 // FIXME all scalers more complex than bilinear could do half of this transform
159 588804 static void chrRangeToJpeg_c(int16_t *dstU, int16_t *dstV, int width,
160 uint32_t _coeff, int64_t _offset)
161 {
162 588804 uint16_t coeff = _coeff;
163 588804 int32_t offset = _offset;
164 int i;
165
2/2
✓ Branch 0 taken 143033908 times.
✓ Branch 1 taken 588804 times.
143622712 for (i = 0; i < width; i++) {
166 143033908 int U = (dstU[i] * coeff + offset) >> 14;
167 143033908 int V = (dstV[i] * coeff + offset) >> 14;
168 143033908 dstU[i] = FFMIN(U, (1 << 15) - 1);
169 143033908 dstV[i] = FFMIN(V, (1 << 15) - 1);
170 }
171 588804 }
172
173 361704 static void chrRangeFromJpeg_c(int16_t *dstU, int16_t *dstV, int width,
174 uint32_t _coeff, int64_t _offset)
175 {
176 361704 uint16_t coeff = _coeff;
177 361704 int32_t offset = _offset;
178 int i;
179
2/2
✓ Branch 0 taken 89800698 times.
✓ Branch 1 taken 361704 times.
90162402 for (i = 0; i < width; i++) {
180 89800698 dstU[i] = (dstU[i] * coeff + offset) >> 14;
181 89800698 dstV[i] = (dstV[i] * coeff + offset) >> 14;
182 }
183 361704 }
184
185 1487905 static void lumRangeToJpeg_c(int16_t *dst, int width,
186 uint32_t _coeff, int64_t _offset)
187 {
188 1487905 uint16_t coeff = _coeff;
189 1487905 int32_t offset = _offset;
190 int i;
191
2/2
✓ Branch 0 taken 514833968 times.
✓ Branch 1 taken 1487905 times.
516321873 for (i = 0; i < width; i++) {
192 514833968 int Y = (dst[i] * coeff + offset) >> 14;
193 514833968 dst[i] = FFMIN(Y, (1 << 15) - 1);
194 }
195 1487905 }
196
197 900198 static void lumRangeFromJpeg_c(int16_t *dst, int width,
198 uint32_t _coeff, int64_t _offset)
199 {
200 900198 uint16_t coeff = _coeff;
201 900198 int32_t offset = _offset;
202 int i;
203
2/2
✓ Branch 0 taken 314115568 times.
✓ Branch 1 taken 900198 times.
315015766 for (i = 0; i < width; i++)
204 314115568 dst[i] = (dst[i] * coeff + offset) >> 14;
205 900198 }
206
207 6 static void chrRangeToJpeg16_c(int16_t *_dstU, int16_t *_dstV, int width,
208 uint32_t coeff, int64_t offset)
209 {
210 int i;
211 6 int32_t *dstU = (int32_t *) _dstU;
212 6 int32_t *dstV = (int32_t *) _dstV;
213
2/2
✓ Branch 0 taken 5784 times.
✓ Branch 1 taken 6 times.
5790 for (i = 0; i < width; i++) {
214 5784 int U = ((int64_t) dstU[i] * coeff + offset) >> 18;
215 5784 int V = ((int64_t) dstV[i] * coeff + offset) >> 18;
216 5784 dstU[i] = FFMIN(U, (1 << 19) - 1);
217 5784 dstV[i] = FFMIN(V, (1 << 19) - 1);
218 }
219 6 }
220
221 6 static void chrRangeFromJpeg16_c(int16_t *_dstU, int16_t *_dstV, int width,
222 uint32_t coeff, int64_t offset)
223 {
224 int i;
225 6 int32_t *dstU = (int32_t *) _dstU;
226 6 int32_t *dstV = (int32_t *) _dstV;
227
2/2
✓ Branch 0 taken 5784 times.
✓ Branch 1 taken 6 times.
5790 for (i = 0; i < width; i++) {
228 5784 dstU[i] = ((int64_t) dstU[i] * coeff + offset) >> 18;
229 5784 dstV[i] = ((int64_t) dstV[i] * coeff + offset) >> 18;
230 }
231 6 }
232
233 254785 static void lumRangeToJpeg16_c(int16_t *_dst, int width,
234 uint32_t coeff, int64_t offset)
235 {
236 int i;
237 254785 int32_t *dst = (int32_t *) _dst;
238
2/2
✓ Branch 0 taken 89616592 times.
✓ Branch 1 taken 254785 times.
89871377 for (i = 0; i < width; i++) {
239 89616592 int Y = ((int64_t) dst[i] * coeff + offset) >> 18;
240 89616592 dst[i] = FFMIN(Y, (1 << 19) - 1);
241 }
242 254785 }
243
244 16594 static void lumRangeFromJpeg16_c(int16_t *_dst, int width,
245 uint32_t coeff, int64_t offset)
246 {
247 int i;
248 16594 int32_t *dst = (int32_t *) _dst;
249
2/2
✓ Branch 0 taken 5844760 times.
✓ Branch 1 taken 16594 times.
5861354 for (i = 0; i < width; i++)
250 5844760 dst[i] = ((int64_t) dst[i] * coeff + offset) >> 18;
251 16594 }
252
253
254 #define DEBUG_SWSCALE_BUFFERS 0
255 #define DEBUG_BUFFERS(...) \
256 if (DEBUG_SWSCALE_BUFFERS) \
257 av_log(c, AV_LOG_DEBUG, __VA_ARGS__)
258
259 525179 int ff_swscale(SwsInternal *c, const uint8_t *const src[], const int srcStride[],
260 int srcSliceY, int srcSliceH, uint8_t *const dst[],
261 const int dstStride[], int dstSliceY, int dstSliceH)
262 {
263
4/4
✓ Branch 0 taken 88275 times.
✓ Branch 1 taken 436904 times.
✓ Branch 2 taken 54734 times.
✓ Branch 3 taken 33541 times.
525179 const int scale_dst = dstSliceY > 0 || dstSliceH < c->opts.dst_h;
264
265 /* load a few things into local vars to make the code more readable?
266 * and faster */
267 525179 const int dstW = c->opts.dst_w;
268 525179 int dstH = c->opts.dst_h;
269
270 525179 const enum AVPixelFormat dstFormat = c->opts.dst_format;
271 525179 const int flags = c->opts.flags;
272 525179 int32_t *vLumFilterPos = c->vLumFilterPos;
273 525179 int32_t *vChrFilterPos = c->vChrFilterPos;
274
275 525179 const int vLumFilterSize = c->vLumFilterSize;
276 525179 const int vChrFilterSize = c->vChrFilterSize;
277
278 525179 yuv2planar1_fn yuv2plane1 = c->yuv2plane1;
279 525179 yuv2planarX_fn yuv2planeX = c->yuv2planeX;
280 525179 yuv2interleavedX_fn yuv2nv12cX = c->yuv2nv12cX;
281 525179 yuv2packed1_fn yuv2packed1 = c->yuv2packed1;
282 525179 yuv2packed2_fn yuv2packed2 = c->yuv2packed2;
283 525179 yuv2packedX_fn yuv2packedX = c->yuv2packedX;
284 525179 yuv2anyX_fn yuv2anyX = c->yuv2anyX;
285 525179 const int chrSrcSliceY = srcSliceY >> c->chrSrcVSubSample;
286 525179 const int chrSrcSliceH = AV_CEIL_RSHIFT(srcSliceH, c->chrSrcVSubSample);
287
4/4
✓ Branch 1 taken 292707 times.
✓ Branch 2 taken 232472 times.
✓ Branch 3 taken 86664 times.
✓ Branch 4 taken 206043 times.
817886 int should_dither = isNBPS(c->opts.src_format) ||
288 292707 is16BPS(c->opts.src_format);
289 int lastDstY;
290
291 /* vars which will change and which we need to store back in the context */
292 525179 int dstY = c->dstY;
293 525179 int lastInLumBuf = c->lastInLumBuf;
294 525179 int lastInChrBuf = c->lastInChrBuf;
295
296 525179 int lumStart = 0;
297 525179 int lumEnd = c->descIndex[0];
298 525179 int chrStart = lumEnd;
299 525179 int chrEnd = c->descIndex[1];
300 525179 int vStart = chrEnd;
301 525179 int vEnd = c->numDesc;
302 525179 SwsSlice *src_slice = &c->slice[lumStart];
303 525179 SwsSlice *hout_slice = &c->slice[c->numSlice-2];
304 525179 SwsSlice *vout_slice = &c->slice[c->numSlice-1];
305 525179 SwsFilterDescriptor *desc = c->desc;
306
307 525179 int needAlpha = c->needAlpha;
308
309 525179 int hasLumHoles = 1;
310 525179 int hasChrHoles = 1;
311
312 const uint8_t *src2[4];
313 int srcStride2[4];
314
315
2/2
✓ Branch 1 taken 113129 times.
✓ Branch 2 taken 412050 times.
525179 if (isPacked(c->opts.src_format)) {
316 113129 src2[0] =
317 113129 src2[1] =
318 113129 src2[2] =
319 113129 src2[3] = src[0];
320 113129 srcStride2[0] =
321 113129 srcStride2[1] =
322 113129 srcStride2[2] =
323 113129 srcStride2[3] = srcStride[0];
324 } else {
325 412050 memcpy(src2, src, sizeof(src2));
326 412050 memcpy(srcStride2, srcStride, sizeof(srcStride2));
327 }
328
329 525179 srcStride2[1] *= 1 << c->vChrDrop;
330 525179 srcStride2[2] *= 1 << c->vChrDrop;
331
332 DEBUG_BUFFERS("swscale() %p[%d] %p[%d] %p[%d] %p[%d] -> %p[%d] %p[%d] %p[%d] %p[%d]\n",
333 src2[0], srcStride2[0], src2[1], srcStride2[1],
334 src2[2], srcStride2[2], src2[3], srcStride2[3],
335 dst[0], dstStride[0], dst[1], dstStride[1],
336 dst[2], dstStride[2], dst[3], dstStride[3]);
337 DEBUG_BUFFERS("srcSliceY: %d srcSliceH: %d dstY: %d dstH: %d\n",
338 srcSliceY, srcSliceH, dstY, dstH);
339 DEBUG_BUFFERS("vLumFilterSize: %d vChrFilterSize: %d\n",
340 vLumFilterSize, vChrFilterSize);
341
342
4/4
✓ Branch 0 taken 519876 times.
✓ Branch 1 taken 5303 times.
✓ Branch 2 taken 508607 times.
✓ Branch 3 taken 11269 times.
525179 if (dstStride[0]&15 || dstStride[1]&15 ||
343
2/4
✓ Branch 0 taken 508607 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 508607 times.
508607 dstStride[2]&15 || dstStride[3]&15) {
344
2/2
✓ Branch 0 taken 10159 times.
✓ Branch 1 taken 6413 times.
16572 SwsInternal *const ctx = c->parent ? sws_internal(c->parent) : c;
345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16572 times.
16572 if (flags & SWS_PRINT_INFO &&
346 !atomic_exchange_explicit(&ctx->stride_unaligned_warned, 1, memory_order_relaxed)) {
347 av_log(c, AV_LOG_WARNING,
348 "Warning: dstStride is not aligned!\n"
349 " ->cannot do aligned memory accesses anymore\n");
350 }
351 }
352
353 #if ARCH_X86
354
5/6
✓ Branch 0 taken 522770 times.
✓ Branch 1 taken 2409 times.
✓ Branch 2 taken 521083 times.
✓ Branch 3 taken 1687 times.
✓ Branch 4 taken 521083 times.
✗ Branch 5 not taken.
525179 if ( (uintptr_t) dst[0]&15 || (uintptr_t) dst[1]&15 || (uintptr_t) dst[2]&15
355
5/6
✓ Branch 0 taken 521068 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 518008 times.
✓ Branch 3 taken 3060 times.
✓ Branch 4 taken 518008 times.
✗ Branch 5 not taken.
521083 || (uintptr_t)src2[0]&15 || (uintptr_t)src2[1]&15 || (uintptr_t)src2[2]&15
356
6/8
✓ Branch 0 taken 514458 times.
✓ Branch 1 taken 3550 times.
✓ Branch 2 taken 505300 times.
✓ Branch 3 taken 9158 times.
✓ Branch 4 taken 505300 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 505300 times.
✗ Branch 7 not taken.
518008 || dstStride[0]&15 || dstStride[1]&15 || dstStride[2]&15 || dstStride[3]&15
357
6/8
✓ Branch 0 taken 505295 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 500145 times.
✓ Branch 3 taken 5150 times.
✓ Branch 4 taken 500145 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 500145 times.
505300 || srcStride2[0]&15 || srcStride2[1]&15 || srcStride2[2]&15 || srcStride2[3]&15
358 ) {
359
2/2
✓ Branch 0 taken 17638 times.
✓ Branch 1 taken 7396 times.
25034 SwsInternal *const ctx = c->parent ? sws_internal(c->parent) : c;
360 25034 int cpu_flags = av_get_cpu_flags();
361
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 25034 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
25034 if (flags & SWS_PRINT_INFO && HAVE_MMXEXT && (cpu_flags & AV_CPU_FLAG_SSE2) &&
362 !atomic_exchange_explicit(&ctx->stride_unaligned_warned,1, memory_order_relaxed)) {
363 av_log(c, AV_LOG_WARNING, "Warning: data is not aligned! This can lead to a speed loss\n");
364 }
365 }
366 #endif
367
368
2/2
✓ Branch 0 taken 491638 times.
✓ Branch 1 taken 33541 times.
525179 if (scale_dst) {
369 491638 dstY = dstSliceY;
370 491638 dstH = dstY + dstSliceH;
371 491638 lastInLumBuf = -1;
372 491638 lastInChrBuf = -1;
373
2/2
✓ Branch 0 taken 33488 times.
✓ Branch 1 taken 53 times.
33541 } else if (srcSliceY == 0) {
374 /* Note the user might start scaling the picture in the middle so this
375 * will not get executed. This is not really intended but works
376 * currently, so people might do it. */
377 33488 dstY = 0;
378 33488 lastInLumBuf = -1;
379 33488 lastInChrBuf = -1;
380 }
381
382
2/2
✓ Branch 0 taken 206043 times.
✓ Branch 1 taken 319136 times.
525179 if (!should_dither) {
383 206043 c->chrDither8 = c->lumDither8 = sws_pb_64;
384 }
385 525179 lastDstY = dstY;
386
387 525179 ff_init_vscale_pfn(c, yuv2plane1, yuv2planeX, yuv2nv12cX,
388 yuv2packed1, yuv2packed2, yuv2packedX, yuv2anyX, c->use_mmx_vfilter);
389
390 525179 ff_init_slice_from_src(src_slice, (uint8_t**)src2, srcStride2, c->opts.src_w,
391 srcSliceY, srcSliceH, chrSrcSliceY, chrSrcSliceH, 1);
392
393 525179 ff_init_slice_from_src(vout_slice, (uint8_t**)dst, dstStride, c->opts.dst_w,
394 525179 dstY, dstSliceH, dstY >> c->chrDstVSubSample,
395 525179 AV_CEIL_RSHIFT(dstSliceH, c->chrDstVSubSample), scale_dst);
396
2/2
✓ Branch 0 taken 525126 times.
✓ Branch 1 taken 53 times.
525179 if (srcSliceY == 0) {
397 525126 hout_slice->plane[0].sliceY = lastInLumBuf + 1;
398 525126 hout_slice->plane[1].sliceY = lastInChrBuf + 1;
399 525126 hout_slice->plane[2].sliceY = lastInChrBuf + 1;
400 525126 hout_slice->plane[3].sliceY = lastInLumBuf + 1;
401
402 525126 hout_slice->plane[0].sliceH =
403 525126 hout_slice->plane[1].sliceH =
404 525126 hout_slice->plane[2].sliceH =
405 525126 hout_slice->plane[3].sliceH = 0;
406 525126 hout_slice->width = dstW;
407 }
408
409
2/2
✓ Branch 0 taken 26441221 times.
✓ Branch 1 taken 525126 times.
26966347 for (; dstY < dstH; dstY++) {
410 26441221 const int chrDstY = dstY >> c->chrDstVSubSample;
411 26441221 int use_mmx_vfilter= c->use_mmx_vfilter;
412
413 // First line needed as input
414 26441221 const int firstLumSrcY = FFMAX(1 - vLumFilterSize, vLumFilterPos[dstY]);
415
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 26441121 times.
26441221 const int firstLumSrcY2 = FFMAX(1 - vLumFilterSize, vLumFilterPos[FFMIN(dstY | ((1 << c->chrDstVSubSample) - 1), c->opts.dst_h - 1)]);
416 // First line needed as input
417 26441221 const int firstChrSrcY = FFMAX(1 - vChrFilterSize, vChrFilterPos[chrDstY]);
418
419 // Last line needed as input
420 26441221 int lastLumSrcY = FFMIN(c->opts.src_h, firstLumSrcY + vLumFilterSize) - 1;
421 26441221 int lastLumSrcY2 = FFMIN(c->opts.src_h, firstLumSrcY2 + vLumFilterSize) - 1;
422 26441221 int lastChrSrcY = FFMIN(c->chrSrcH, firstChrSrcY + vChrFilterSize) - 1;
423 int enough_lines;
424
425 int i;
426 int posY, cPosY, firstPosY, lastPosY, firstCPosY, lastCPosY;
427
428 // handle holes (FAST_BILINEAR & weird filters)
429
2/2
✓ Branch 0 taken 22615554 times.
✓ Branch 1 taken 3825667 times.
26441221 if (firstLumSrcY > lastInLumBuf) {
430
431 22615554 hasLumHoles = lastInLumBuf != firstLumSrcY - 1;
432
2/2
✓ Branch 0 taken 621004 times.
✓ Branch 1 taken 21994550 times.
22615554 if (hasLumHoles) {
433 621004 hout_slice->plane[0].sliceY = firstLumSrcY;
434 621004 hout_slice->plane[3].sliceY = firstLumSrcY;
435 621004 hout_slice->plane[0].sliceH =
436 621004 hout_slice->plane[3].sliceH = 0;
437 }
438
439 22615554 lastInLumBuf = firstLumSrcY - 1;
440 }
441
2/2
✓ Branch 0 taken 12378179 times.
✓ Branch 1 taken 14063042 times.
26441221 if (firstChrSrcY > lastInChrBuf) {
442
443 12378179 hasChrHoles = lastInChrBuf != firstChrSrcY - 1;
444
2/2
✓ Branch 0 taken 772804 times.
✓ Branch 1 taken 11605375 times.
12378179 if (hasChrHoles) {
445 772804 hout_slice->plane[1].sliceY = firstChrSrcY;
446 772804 hout_slice->plane[2].sliceY = firstChrSrcY;
447 772804 hout_slice->plane[1].sliceH =
448 772804 hout_slice->plane[2].sliceH = 0;
449 }
450
451 12378179 lastInChrBuf = firstChrSrcY - 1;
452 }
453
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);
459
460 // Do we have enough lines in this slice to output the dstY line
461
2/2
✓ Branch 0 taken 26441172 times.
✓ Branch 1 taken 49 times.
52882393 enough_lines = lastLumSrcY2 < srcSliceY + srcSliceH &&
462
2/2
✓ Branch 0 taken 26441168 times.
✓ Branch 1 taken 4 times.
26441172 lastChrSrcY < AV_CEIL_RSHIFT(srcSliceY + srcSliceH, c->chrSrcVSubSample);
463
464
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 26441168 times.
26441221 if (!enough_lines) {
465 53 lastLumSrcY = srcSliceY + srcSliceH - 1;
466 53 lastChrSrcY = chrSrcSliceY + chrSrcSliceH - 1;
467 DEBUG_BUFFERS("buffering slice: lastLumSrcY %d lastChrSrcY %d\n",
468 lastLumSrcY, lastChrSrcY);
469 }
470
471
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26441221 times.
26441221 av_assert0((lastLumSrcY - firstLumSrcY + 1) <= hout_slice->plane[0].available_lines);
472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26441221 times.
26441221 av_assert0((lastChrSrcY - firstChrSrcY + 1) <= hout_slice->plane[1].available_lines);
473
474
475 26441221 posY = hout_slice->plane[0].sliceY + hout_slice->plane[0].sliceH;
476
4/4
✓ Branch 0 taken 5376831 times.
✓ Branch 1 taken 21064390 times.
✓ Branch 2 taken 4479091 times.
✓ Branch 3 taken 897740 times.
26441221 if (posY <= lastLumSrcY && !hasLumHoles) {
477 4479091 firstPosY = FFMAX(firstLumSrcY, posY);
478
2/2
✓ Branch 0 taken 73620 times.
✓ Branch 1 taken 4405471 times.
4479091 lastPosY = FFMIN(firstLumSrcY + hout_slice->plane[0].available_lines - 1, srcSliceY + srcSliceH - 1);
479 } else {
480 21962130 firstPosY = posY;
481 21962130 lastPosY = lastLumSrcY;
482 }
483
484 26441221 cPosY = hout_slice->plane[1].sliceY + hout_slice->plane[1].sliceH;
485
4/4
✓ Branch 0 taken 6086902 times.
✓ Branch 1 taken 20354319 times.
✓ Branch 2 taken 3344146 times.
✓ Branch 3 taken 2742756 times.
26441221 if (cPosY <= lastChrSrcY && !hasChrHoles) {
486 3344146 firstCPosY = FFMAX(firstChrSrcY, cPosY);
487 3344146 lastCPosY = FFMIN(firstChrSrcY + hout_slice->plane[1].available_lines - 1, AV_CEIL_RSHIFT(srcSliceY + srcSliceH, c->chrSrcVSubSample) - 1);
488 } else {
489 23097075 firstCPosY = cPosY;
490 23097075 lastCPosY = lastChrSrcY;
491 }
492
493 26441221 ff_rotate_slice(hout_slice, lastPosY, lastCPosY);
494
495
2/2
✓ Branch 0 taken 5376831 times.
✓ Branch 1 taken 21064390 times.
26441221 if (posY < lastLumSrcY + 1) {
496
2/2
✓ Branch 0 taken 7875475 times.
✓ Branch 1 taken 5376831 times.
13252306 for (i = lumStart; i < lumEnd; ++i)
497 7875475 desc[i].process(c, &desc[i], firstPosY, lastPosY - firstPosY + 1);
498 }
499
500 26441221 lastInLumBuf = lastLumSrcY;
501
502
2/2
✓ Branch 0 taken 6086902 times.
✓ Branch 1 taken 20354319 times.
26441221 if (cPosY < lastChrSrcY + 1) {
503
2/2
✓ Branch 0 taken 9537904 times.
✓ Branch 1 taken 6086902 times.
15624806 for (i = chrStart; i < chrEnd; ++i)
504 9537904 desc[i].process(c, &desc[i], firstCPosY, lastCPosY - firstCPosY + 1);
505 }
506
507 26441221 lastInChrBuf = lastChrSrcY;
508
509
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 26441168 times.
26441221 if (!enough_lines)
510 53 break; // we can't output a dstY line so let's try with the next slice
511
512 #if HAVE_MMX_INLINE
513 26441168 ff_updateMMXDitherTables(c, dstY);
514 26441168 c->dstW_mmx = c->opts.dst_w;
515 #endif
516
2/2
✓ Branch 0 taken 12971289 times.
✓ Branch 1 taken 13469879 times.
26441168 if (should_dither) {
517 12971289 c->chrDither8 = ff_dither_8x8_128[chrDstY & 7];
518 12971289 c->lumDither8 = ff_dither_8x8_128[dstY & 7];
519 }
520
2/2
✓ Branch 0 taken 176444 times.
✓ Branch 1 taken 26264724 times.
26441168 if (dstY >= c->opts.dst_h - 2) {
521 /* hmm looks like we can't use MMX here without overwriting
522 * this array's tail */
523 176444 ff_sws_init_output_funcs(c, &yuv2plane1, &yuv2planeX, &yuv2nv12cX,
524 &yuv2packed1, &yuv2packed2, &yuv2packedX, &yuv2anyX);
525 176444 use_mmx_vfilter= 0;
526 176444 ff_init_vscale_pfn(c, yuv2plane1, yuv2planeX, yuv2nv12cX,
527 yuv2packed1, yuv2packed2, yuv2packedX, yuv2anyX, use_mmx_vfilter);
528 }
529
530
2/2
✓ Branch 0 taken 43658636 times.
✓ Branch 1 taken 26441168 times.
70099804 for (i = vStart; i < vEnd; ++i)
531 43658636 desc[i].process(c, &desc[i], dstY, 1);
532 }
533
6/6
✓ Branch 1 taken 385343 times.
✓ Branch 2 taken 139836 times.
✓ Branch 4 taken 8284 times.
✓ Branch 5 taken 377059 times.
✓ Branch 6 taken 6438 times.
✓ Branch 7 taken 1846 times.
525179 if (isPlanar(dstFormat) && isALPHA(dstFormat) && !needAlpha) {
534 6438 int offset = lastDstY - dstSliceY;
535 6438 int length = dstW;
536 6438 int height = dstY - lastDstY;
537
538
4/4
✓ Branch 1 taken 6082 times.
✓ Branch 2 taken 356 times.
✓ Branch 4 taken 424 times.
✓ Branch 5 taken 5658 times.
7218 if (is16BPS(dstFormat) || isNBPS(dstFormat)) {
539 780 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(dstFormat);
540 780 fillPlane16(dst[3], dstStride[3], length, height, offset,
541 780 1, desc->comp[3].depth,
542 isBE(dstFormat));
543
2/2
✓ Branch 1 taken 92 times.
✓ Branch 2 taken 5566 times.
5658 } else if (is32BPS(dstFormat)) {
544 92 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(dstFormat);
545 184 fillPlane32(dst[3], dstStride[3], length, height, offset,
546 92 1, desc->comp[3].depth,
547 92 isBE(dstFormat), desc->flags & AV_PIX_FMT_FLAG_FLOAT);
548 } else
549 5566 fillPlane(dst[3], dstStride[3], length, height, offset, 255);
550 }
551
552 #if HAVE_MMXEXT_INLINE
553
2/2
✓ Branch 1 taken 135 times.
✓ Branch 2 taken 525044 times.
525179 if (av_get_cpu_flags() & AV_CPU_FLAG_MMXEXT)
554 135 __asm__ volatile ("sfence" ::: "memory");
555 #endif
556 525179 emms_c();
557
558 /* store changed local vars back in the context */
559 525179 c->dstY = dstY;
560 525179 c->lastInLumBuf = lastInLumBuf;
561 525179 c->lastInChrBuf = lastInChrBuf;
562
563 525179 return dstY - lastDstY;
564 }
565
566 /*
567 * Solve for coeff and offset:
568 * dst = ((src << src_shift) * coeff + offset) >> (mult_shift + src_shift)
569 *
570 * If SwsInternal->dstBpc is > 14, coeff is uint16_t and offset is int32_t,
571 * otherwise (SwsInternal->dstBpc is <= 14) coeff is uint32_t and offset is
572 * int64_t.
573 */
574 10326 static void solve_range_convert(uint16_t src_min, uint16_t src_max,
575 uint16_t dst_min, uint16_t dst_max,
576 int src_bits, int src_shift, int mult_shift,
577 uint32_t *coeff, int64_t *offset)
578 {
579 10326 uint16_t src_range = src_max - src_min;
580 10326 uint16_t dst_range = dst_max - dst_min;
581 10326 int total_shift = mult_shift + src_shift;
582 10326 *coeff = AV_CEIL_RSHIFT(((uint64_t) dst_range << total_shift) / src_range, src_shift);
583 10326 *offset = ((int64_t) dst_max << total_shift) -
584 10326 ((int64_t) src_max << src_shift) * *coeff;
585 10326 }
586
587 5163 static void init_range_convert_constants(SwsInternal *c)
588 {
589
2/2
✓ Branch 0 taken 2743 times.
✓ Branch 1 taken 2420 times.
5163 const int bit_depth = c->dstBpc ? FFMIN(c->dstBpc, 16) : 8;
590
2/2
✓ Branch 0 taken 4767 times.
✓ Branch 1 taken 396 times.
5163 const int src_bits = bit_depth <= 14 ? 15 : 19;
591 5163 const int src_shift = src_bits - bit_depth;
592
2/2
✓ Branch 0 taken 4767 times.
✓ Branch 1 taken 396 times.
5163 const int mult_shift = bit_depth <= 14 ? 14 : 18;
593 5163 const uint16_t mpeg_min = 16U << (bit_depth - 8);
594 5163 const uint16_t mpeg_max_lum = 235U << (bit_depth - 8);
595 5163 const uint16_t mpeg_max_chr = 240U << (bit_depth - 8);
596 5163 const uint16_t jpeg_max = (1U << bit_depth) - 1;
597 uint16_t src_min, src_max_lum, src_max_chr;
598 uint16_t dst_min, dst_max_lum, dst_max_chr;
599
2/2
✓ Branch 0 taken 1610 times.
✓ Branch 1 taken 3553 times.
5163 if (c->opts.src_range) {
600 1610 src_min = 0;
601 1610 src_max_lum = jpeg_max;
602 1610 src_max_chr = jpeg_max;
603 1610 dst_min = mpeg_min;
604 1610 dst_max_lum = mpeg_max_lum;
605 1610 dst_max_chr = mpeg_max_chr;
606 } else {
607 3553 src_min = mpeg_min;
608 3553 src_max_lum = mpeg_max_lum;
609 3553 src_max_chr = mpeg_max_chr;
610 3553 dst_min = 0;
611 3553 dst_max_lum = jpeg_max;
612 3553 dst_max_chr = jpeg_max;
613 }
614 5163 solve_range_convert(src_min, src_max_lum, dst_min, dst_max_lum,
615 src_bits, src_shift, mult_shift,
616 &c->lumConvertRange_coeff, &c->lumConvertRange_offset);
617 5163 solve_range_convert(src_min, src_max_chr, dst_min, dst_max_chr,
618 src_bits, src_shift, mult_shift,
619 &c->chrConvertRange_coeff, &c->chrConvertRange_offset);
620 5163 }
621
622 70068 av_cold void ff_sws_init_range_convert(SwsInternal *c)
623 {
624 70068 c->lumConvertRange = NULL;
625 70068 c->chrConvertRange = NULL;
626
5/6
✓ Branch 0 taken 6437 times.
✓ Branch 1 taken 63631 times.
✓ Branch 3 taken 5163 times.
✓ Branch 4 taken 1274 times.
✓ Branch 5 taken 5163 times.
✗ Branch 6 not taken.
70068 if (c->opts.src_range != c->opts.dst_range && !isAnyRGB(c->opts.dst_format) && c->dstBpc < 32) {
627 5163 init_range_convert_constants(c);
628
2/2
✓ Branch 0 taken 4767 times.
✓ Branch 1 taken 396 times.
5163 if (c->dstBpc <= 14) {
629
2/2
✓ Branch 0 taken 1564 times.
✓ Branch 1 taken 3203 times.
4767 if (c->opts.src_range) {
630 1564 c->lumConvertRange = lumRangeFromJpeg_c;
631 1564 c->chrConvertRange = chrRangeFromJpeg_c;
632 } else {
633 3203 c->lumConvertRange = lumRangeToJpeg_c;
634 3203 c->chrConvertRange = chrRangeToJpeg_c;
635 }
636 } else {
637
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 350 times.
396 if (c->opts.src_range) {
638 46 c->lumConvertRange = lumRangeFromJpeg16_c;
639 46 c->chrConvertRange = chrRangeFromJpeg16_c;
640 } else {
641 350 c->lumConvertRange = lumRangeToJpeg16_c;
642 350 c->chrConvertRange = chrRangeToJpeg16_c;
643 }
644 }
645
646 #if ARCH_AARCH64
647 ff_sws_init_range_convert_aarch64(c);
648 #elif ARCH_LOONGARCH64
649 ff_sws_init_range_convert_loongarch(c);
650 #elif ARCH_RISCV
651 ff_sws_init_range_convert_riscv(c);
652 #elif ARCH_X86
653 5163 ff_sws_init_range_convert_x86(c);
654 #endif
655 }
656 70068 }
657
658 38530 static av_cold void sws_init_swscale(SwsInternal *c)
659 {
660 38530 enum AVPixelFormat srcFormat = c->opts.src_format;
661
662 38530 ff_sws_init_output_funcs(c, &c->yuv2plane1, &c->yuv2planeX,
663 &c->yuv2nv12cX, &c->yuv2packed1,
664 &c->yuv2packed2, &c->yuv2packedX, &c->yuv2anyX);
665
666 38530 ff_sws_init_input_funcs(c, &c->lumToYV12, &c->alpToYV12, &c->chrToYV12,
667 &c->readLumPlanar, &c->readAlpPlanar, &c->readChrPlanar);
668
669
2/2
✓ Branch 0 taken 21212 times.
✓ Branch 1 taken 17318 times.
38530 if (c->srcBpc == 8) {
670
2/2
✓ Branch 0 taken 19221 times.
✓ Branch 1 taken 1991 times.
21212 if (c->dstBpc <= 14) {
671 19221 c->hyScale = c->hcScale = hScale8To15_c;
672
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19221 times.
19221 if (c->opts.flags & SWS_FAST_BILINEAR) {
673 c->hyscale_fast = ff_hyscale_fast_c;
674 c->hcscale_fast = ff_hcscale_fast_c;
675 }
676 } else {
677 1991 c->hyScale = c->hcScale = hScale8To19_c;
678 }
679 } else {
680 17318 c->hyScale = c->hcScale = c->dstBpc > 14 ? hScale16To19_c
681
2/2
✓ Branch 0 taken 3575 times.
✓ Branch 1 taken 13743 times.
17318 : hScale16To15_c;
682 }
683
684 38530 ff_sws_init_range_convert(c);
685
686
8/8
✓ Branch 1 taken 37625 times.
✓ Branch 2 taken 905 times.
✓ Branch 4 taken 36523 times.
✓ Branch 5 taken 1102 times.
✓ Branch 6 taken 36411 times.
✓ Branch 7 taken 112 times.
✓ Branch 8 taken 36295 times.
✓ Branch 9 taken 116 times.
38530 if (!(isGray(srcFormat) || isGray(c->opts.dst_format) ||
687 srcFormat == AV_PIX_FMT_MONOBLACK || srcFormat == AV_PIX_FMT_MONOWHITE))
688 36295 c->needs_hcscale = 1;
689 38530 }
690
691 38530 void ff_sws_init_scale(SwsInternal *c)
692 {
693 38530 sws_init_swscale(c);
694
695 #if ARCH_PPC
696 ff_sws_init_swscale_ppc(c);
697 #elif ARCH_X86
698 38530 ff_sws_init_swscale_x86(c);
699 #elif ARCH_AARCH64
700 ff_sws_init_swscale_aarch64(c);
701 #elif ARCH_ARM
702 ff_sws_init_swscale_arm(c);
703 #elif ARCH_LOONGARCH64
704 ff_sws_init_swscale_loongarch(c);
705 #elif ARCH_RISCV
706 ff_sws_init_swscale_riscv(c);
707 #endif
708 38530 }
709
710 270 static void reset_ptr(const uint8_t *src[], enum AVPixelFormat format)
711 {
712
2/2
✓ Branch 1 taken 236 times.
✓ Branch 2 taken 34 times.
270 if (!isALPHA(format))
713 236 src[3] = NULL;
714
2/2
✓ Branch 1 taken 103 times.
✓ Branch 2 taken 167 times.
270 if (!isPlanar(format)) {
715 103 src[3] = src[2] = NULL;
716
717
1/2
✓ Branch 1 taken 103 times.
✗ Branch 2 not taken.
103 if (!usePal(format))
718 103 src[1] = NULL;
719 }
720 270 }
721
722 270 static int check_image_pointers(const uint8_t * const data[4], enum AVPixelFormat pix_fmt,
723 const int linesizes[4])
724 {
725 270 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
726 int i;
727
728 av_assert2(desc);
729
730
2/2
✓ Branch 0 taken 1080 times.
✓ Branch 1 taken 270 times.
1350 for (i = 0; i < 4; i++) {
731 1080 int plane = desc->comp[i].plane;
732
2/4
✓ Branch 0 taken 1080 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1080 times.
1080 if (!data[plane] || !linesizes[plane])
733 return 0;
734 }
735
736 270 return 1;
737 }
738
739 2577 void ff_xyz12Torgb48(const SwsInternal *c, uint8_t *dst, int dst_stride,
740 const uint8_t *src, int src_stride, int w, int h)
741 {
742 2577 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
743
744
2/2
✓ Branch 0 taken 83232 times.
✓ Branch 1 taken 2577 times.
85809 for (int yp = 0; yp < h; yp++) {
745 83232 const uint16_t *src16 = (const uint16_t *) src;
746 83232 uint16_t *dst16 = (uint16_t *) dst;
747
748
2/2
✓ Branch 0 taken 29297664 times.
✓ Branch 1 taken 83232 times.
29380896 for (int xp = 0; xp < 3 * w; xp += 3) {
749 int x, y, z, r, g, b;
750
751
2/2
✓ Branch 0 taken 101376 times.
✓ Branch 1 taken 29196288 times.
29297664 if (desc->flags & AV_PIX_FMT_FLAG_BE) {
752 101376 x = AV_RB16(src16 + xp + 0);
753 101376 y = AV_RB16(src16 + xp + 1);
754 101376 z = AV_RB16(src16 + xp + 2);
755 } else {
756 29196288 x = AV_RL16(src16 + xp + 0);
757 29196288 y = AV_RL16(src16 + xp + 1);
758 29196288 z = AV_RL16(src16 + xp + 2);
759 }
760
761 29297664 x = c->xyzgamma[x >> 4];
762 29297664 y = c->xyzgamma[y >> 4];
763 29297664 z = c->xyzgamma[z >> 4];
764
765 // convert from XYZlinear to sRGBlinear
766 29297664 r = c->xyz2rgb_matrix[0][0] * x +
767 29297664 c->xyz2rgb_matrix[0][1] * y +
768 29297664 c->xyz2rgb_matrix[0][2] * z >> 12;
769 29297664 g = c->xyz2rgb_matrix[1][0] * x +
770 29297664 c->xyz2rgb_matrix[1][1] * y +
771 29297664 c->xyz2rgb_matrix[1][2] * z >> 12;
772 29297664 b = c->xyz2rgb_matrix[2][0] * x +
773 29297664 c->xyz2rgb_matrix[2][1] * y +
774 29297664 c->xyz2rgb_matrix[2][2] * z >> 12;
775
776 // limit values to 16-bit depth
777 29297664 r = av_clip_uint16(r);
778 29297664 g = av_clip_uint16(g);
779 29297664 b = av_clip_uint16(b);
780
781 // convert from sRGBlinear to RGB and scale from 12bit to 16bit
782
2/2
✓ Branch 0 taken 101376 times.
✓ Branch 1 taken 29196288 times.
29297664 if (desc->flags & AV_PIX_FMT_FLAG_BE) {
783 101376 AV_WB16(dst16 + xp + 0, c->rgbgamma[r] << 4);
784 101376 AV_WB16(dst16 + xp + 1, c->rgbgamma[g] << 4);
785 101376 AV_WB16(dst16 + xp + 2, c->rgbgamma[b] << 4);
786 } else {
787 29196288 AV_WL16(dst16 + xp + 0, c->rgbgamma[r] << 4);
788 29196288 AV_WL16(dst16 + xp + 1, c->rgbgamma[g] << 4);
789 29196288 AV_WL16(dst16 + xp + 2, c->rgbgamma[b] << 4);
790 }
791 }
792
793 83232 src += src_stride;
794 83232 dst += dst_stride;
795 }
796 2577 }
797
798 2618 void ff_rgb48Toxyz12(const SwsInternal *c, uint8_t *dst, int dst_stride,
799 const uint8_t *src, int src_stride, int w, int h)
800 {
801 2618 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.dst_format);
802
803
2/2
✓ Branch 0 taken 94664 times.
✓ Branch 1 taken 2618 times.
97282 for (int yp = 0; yp < h; yp++) {
804 94664 uint16_t *src16 = (uint16_t *) src;
805 94664 uint16_t *dst16 = (uint16_t *) dst;
806
807
2/2
✓ Branch 0 taken 33291328 times.
✓ Branch 1 taken 94664 times.
33385992 for (int xp = 0; xp < 3 * w; xp += 3) {
808 int x, y, z, r, g, b;
809
810
2/2
✓ Branch 0 taken 2047520 times.
✓ Branch 1 taken 31243808 times.
33291328 if (desc->flags & AV_PIX_FMT_FLAG_BE) {
811 2047520 r = AV_RB16(src16 + xp + 0);
812 2047520 g = AV_RB16(src16 + xp + 1);
813 2047520 b = AV_RB16(src16 + xp + 2);
814 } else {
815 31243808 r = AV_RL16(src16 + xp + 0);
816 31243808 g = AV_RL16(src16 + xp + 1);
817 31243808 b = AV_RL16(src16 + xp + 2);
818 }
819
820 33291328 r = c->rgbgammainv[r>>4];
821 33291328 g = c->rgbgammainv[g>>4];
822 33291328 b = c->rgbgammainv[b>>4];
823
824 // convert from sRGBlinear to XYZlinear
825 33291328 x = c->rgb2xyz_matrix[0][0] * r +
826 33291328 c->rgb2xyz_matrix[0][1] * g +
827 33291328 c->rgb2xyz_matrix[0][2] * b >> 12;
828 33291328 y = c->rgb2xyz_matrix[1][0] * r +
829 33291328 c->rgb2xyz_matrix[1][1] * g +
830 33291328 c->rgb2xyz_matrix[1][2] * b >> 12;
831 33291328 z = c->rgb2xyz_matrix[2][0] * r +
832 33291328 c->rgb2xyz_matrix[2][1] * g +
833 33291328 c->rgb2xyz_matrix[2][2] * b >> 12;
834
835 // limit values to 16-bit depth
836 33291328 x = av_clip_uint16(x);
837 33291328 y = av_clip_uint16(y);
838 33291328 z = av_clip_uint16(z);
839
840 // convert from XYZlinear to X'Y'Z' and scale from 12bit to 16bit
841
2/2
✓ Branch 0 taken 2047520 times.
✓ Branch 1 taken 31243808 times.
33291328 if (desc->flags & AV_PIX_FMT_FLAG_BE) {
842 2047520 AV_WB16(dst16 + xp + 0, c->xyzgammainv[x] << 4);
843 2047520 AV_WB16(dst16 + xp + 1, c->xyzgammainv[y] << 4);
844 2047520 AV_WB16(dst16 + xp + 2, c->xyzgammainv[z] << 4);
845 } else {
846 31243808 AV_WL16(dst16 + xp + 0, c->xyzgammainv[x] << 4);
847 31243808 AV_WL16(dst16 + xp + 1, c->xyzgammainv[y] << 4);
848 31243808 AV_WL16(dst16 + xp + 2, c->xyzgammainv[z] << 4);
849 }
850 }
851
852 94664 src += src_stride;
853 94664 dst += dst_stride;
854 }
855 2618 }
856
857 4713 void ff_update_palette(SwsInternal *c, const uint32_t *pal)
858 {
859
2/2
✓ Branch 0 taken 1206528 times.
✓ Branch 1 taken 4713 times.
1211241 for (int i = 0; i < 256; i++) {
860 1206528 int r, g, b, y, u, v, a = 0xff;
861
2/2
✓ Branch 0 taken 1118464 times.
✓ Branch 1 taken 88064 times.
1206528 if (c->opts.src_format == AV_PIX_FMT_PAL8) {
862 1118464 uint32_t p = pal[i];
863 1118464 a = (p >> 24) & 0xFF;
864 1118464 r = (p >> 16) & 0xFF;
865 1118464 g = (p >> 8) & 0xFF;
866 1118464 b = p & 0xFF;
867
2/2
✓ Branch 0 taken 256 times.
✓ Branch 1 taken 87808 times.
88064 } else if (c->opts.src_format == AV_PIX_FMT_RGB8) {
868 256 r = ( i >> 5 ) * 36;
869 256 g = ((i >> 2) & 7) * 36;
870 256 b = ( i & 3) * 85;
871
2/2
✓ Branch 0 taken 256 times.
✓ Branch 1 taken 87552 times.
87808 } else if (c->opts.src_format == AV_PIX_FMT_BGR8) {
872 256 b = ( i >> 6 ) * 85;
873 256 g = ((i >> 3) & 7) * 36;
874 256 r = ( i & 7) * 36;
875
2/2
✓ Branch 0 taken 256 times.
✓ Branch 1 taken 87296 times.
87552 } else if (c->opts.src_format == AV_PIX_FMT_RGB4_BYTE) {
876 256 r = ( i >> 3 ) * 255;
877 256 g = ((i >> 1) & 3) * 85;
878 256 b = ( i & 1) * 255;
879
3/4
✓ Branch 0 taken 256 times.
✓ Branch 1 taken 87040 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 256 times.
87296 } else if (c->opts.src_format == AV_PIX_FMT_GRAY8 || c->opts.src_format == AV_PIX_FMT_GRAY8A) {
880 87040 r = g = b = i;
881 } else {
882 av_assert1(c->opts.src_format == AV_PIX_FMT_BGR4_BYTE);
883 256 b = ( i >> 3 ) * 255;
884 256 g = ((i >> 1) & 3) * 85;
885 256 r = ( i & 1) * 255;
886 }
887 #define RGB2YUV_SHIFT 15
888 #define BY ( (int) (0.114 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
889 #define BV (-(int) (0.081 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
890 #define BU ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
891 #define GY ( (int) (0.587 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
892 #define GV (-(int) (0.419 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
893 #define GU (-(int) (0.331 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
894 #define RY ( (int) (0.299 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
895 #define RV ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
896 #define RU (-(int) (0.169 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
897
898 1206528 y = av_clip_uint8((RY * r + GY * g + BY * b + ( 33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
899 1206528 u = av_clip_uint8((RU * r + GU * g + BU * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
900 1206528 v = av_clip_uint8((RV * r + GV * g + BV * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
901 1206528 c->pal_yuv[i]= y + (u<<8) + (v<<16) + ((unsigned)a<<24);
902
903
3/5
✓ Branch 0 taken 855552 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6656 times.
✓ Branch 4 taken 344320 times.
1206528 switch (c->opts.dst_format) {
904 855552 case AV_PIX_FMT_BGR32:
905 #if !HAVE_BIGENDIAN
906 case AV_PIX_FMT_RGB24:
907 #endif
908 855552 c->pal_rgb[i]= r + (g<<8) + (b<<16) + ((unsigned)a<<24);
909 855552 break;
910 case AV_PIX_FMT_BGR32_1:
911 #if HAVE_BIGENDIAN
912 case AV_PIX_FMT_BGR24:
913 #endif
914 c->pal_rgb[i]= a + (r<<8) + (g<<16) + ((unsigned)b<<24);
915 break;
916 case AV_PIX_FMT_RGB32_1:
917 #if HAVE_BIGENDIAN
918 case AV_PIX_FMT_RGB24:
919 #endif
920 c->pal_rgb[i]= a + (b<<8) + (g<<16) + ((unsigned)r<<24);
921 break;
922 6656 case AV_PIX_FMT_GBRP:
923 case AV_PIX_FMT_GBRAP:
924 #if HAVE_BIGENDIAN
925 c->pal_rgb[i]= a + (r<<8) + (b<<16) + ((unsigned)g<<24);
926 #else
927 6656 c->pal_rgb[i]= g + (b<<8) + (r<<16) + ((unsigned)a<<24);
928 #endif
929 6656 break;
930 344320 case AV_PIX_FMT_RGB32:
931 #if !HAVE_BIGENDIAN
932 case AV_PIX_FMT_BGR24:
933 #endif
934 default:
935 344320 c->pal_rgb[i]= b + (g<<8) + (r<<16) + ((unsigned)a<<24);
936 }
937 }
938 4713 }
939
940 static int scale_internal(SwsContext *sws,
941 const uint8_t * const srcSlice[], const int srcStride[],
942 int srcSliceY, int srcSliceH,
943 uint8_t *const dstSlice[], const int dstStride[],
944 int dstSliceY, int dstSliceH);
945
946 static int scale_gamma(SwsInternal *c,
947 const uint8_t * const srcSlice[], const int srcStride[],
948 int srcSliceY, int srcSliceH,
949 uint8_t * const dstSlice[], const int dstStride[],
950 int dstSliceY, int dstSliceH)
951 {
952 int ret = scale_internal(c->cascaded_context[0],
953 srcSlice, srcStride, srcSliceY, srcSliceH,
954 c->cascaded_tmp[0], c->cascaded_tmpStride[0], 0, c->opts.src_h);
955
956 if (ret < 0)
957 return ret;
958
959 if (c->cascaded_context[2])
960 ret = scale_internal(c->cascaded_context[1], (const uint8_t * const *)c->cascaded_tmp[0],
961 c->cascaded_tmpStride[0], srcSliceY, srcSliceH,
962 c->cascaded_tmp[1], c->cascaded_tmpStride[1], 0, c->opts.dst_h);
963 else
964 ret = scale_internal(c->cascaded_context[1], (const uint8_t * const *)c->cascaded_tmp[0],
965 c->cascaded_tmpStride[0], srcSliceY, srcSliceH,
966 dstSlice, dstStride, dstSliceY, dstSliceH);
967
968 if (ret < 0)
969 return ret;
970
971 if (c->cascaded_context[2]) {
972 const int dstY1 = sws_internal(c->cascaded_context[1])->dstY;
973 ret = scale_internal(c->cascaded_context[2], (const uint8_t * const *)c->cascaded_tmp[1],
974 c->cascaded_tmpStride[1], dstY1 - ret, dstY1,
975 dstSlice, dstStride, dstSliceY, dstSliceH);
976 }
977 return ret;
978 }
979
980 static int scale_cascaded(SwsInternal *c,
981 const uint8_t * const srcSlice[], const int srcStride[],
982 int srcSliceY, int srcSliceH,
983 uint8_t * const dstSlice[], const int dstStride[],
984 int dstSliceY, int dstSliceH)
985 {
986 const int dstH0 = c->cascaded_context[0]->dst_h;
987 int ret = scale_internal(c->cascaded_context[0],
988 srcSlice, srcStride, srcSliceY, srcSliceH,
989 c->cascaded_tmp[0], c->cascaded_tmpStride[0],
990 0, dstH0);
991 if (ret < 0)
992 return ret;
993 ret = scale_internal(c->cascaded_context[1],
994 (const uint8_t * const * )c->cascaded_tmp[0], c->cascaded_tmpStride[0],
995 0, dstH0, dstSlice, dstStride, dstSliceY, dstSliceH);
996 return ret;
997 }
998
999 135 static int scale_internal(SwsContext *sws,
1000 const uint8_t * const srcSlice[], const int srcStride[],
1001 int srcSliceY, int srcSliceH,
1002 uint8_t *const dstSlice[], const int dstStride[],
1003 int dstSliceY, int dstSliceH)
1004 {
1005 135 SwsInternal *c = sws_internal(sws);
1006
2/4
✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 135 times.
135 const int scale_dst = dstSliceY > 0 || dstSliceH < sws->dst_h;
1007
3/4
✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 82 times.
✓ Branch 3 taken 53 times.
135 const int frame_start = scale_dst || !c->sliceDir;
1008 int i, ret;
1009 const uint8_t *src2[4];
1010 uint8_t *dst2[4];
1011
1/2
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
135 int macro_height_src = isBayer(sws->src_format) ? 2 : (1 << c->chrSrcVSubSample);
1012
1/2
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
135 int macro_height_dst = isBayer(sws->dst_format) ? 2 : (1 << c->chrDstVSubSample);
1013 // copy strides, so they can safely be modified
1014 int srcStride2[4];
1015 int dstStride2[4];
1016 135 int srcSliceY_internal = srcSliceY;
1017
1018
4/8
✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 135 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 135 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 135 times.
135 if (!srcStride || !dstStride || !dstSlice || !srcSlice) {
1019 av_log(c, AV_LOG_ERROR, "One of the input parameters to sws_scale() is NULL, please check the calling code\n");
1020 return AVERROR(EINVAL);
1021 }
1022
1023
1/2
✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
135 if ((srcSliceY & (macro_height_src - 1)) ||
1024
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
135 ((srcSliceH & (macro_height_src - 1)) && srcSliceY + srcSliceH != sws->src_h) ||
1025
2/4
✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 135 times.
270 srcSliceY + srcSliceH > sws->src_h ||
1026
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
135 (isBayer(sws->src_format) && srcSliceH <= 1)) {
1027 av_log(c, AV_LOG_ERROR, "Slice parameters %d, %d are invalid\n", srcSliceY, srcSliceH);
1028 return AVERROR(EINVAL);
1029 }
1030
1031
1/2
✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
135 if ((dstSliceY & (macro_height_dst - 1)) ||
1032
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
135 ((dstSliceH & (macro_height_dst - 1)) && dstSliceY + dstSliceH != sws->dst_h) ||
1033
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
135 dstSliceY + dstSliceH > sws->dst_h) {
1034 av_log(c, AV_LOG_ERROR, "Slice parameters %d, %d are invalid\n", dstSliceY, dstSliceH);
1035 return AVERROR(EINVAL);
1036 }
1037
1038
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 135 times.
135 if (!check_image_pointers(srcSlice, sws->src_format, srcStride)) {
1039 av_log(c, AV_LOG_ERROR, "bad src image pointers\n");
1040 return AVERROR(EINVAL);
1041 }
1042
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 135 times.
135 if (!check_image_pointers((const uint8_t* const*)dstSlice, sws->dst_format, dstStride)) {
1043 av_log(c, AV_LOG_ERROR, "bad dst image pointers\n");
1044 return AVERROR(EINVAL);
1045 }
1046
1047 // do not mess up sliceDir if we have a "trailing" 0-size slice
1048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
135 if (srcSliceH == 0)
1049 return 0;
1050
1051
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
135 if (sws->gamma_flag && c->cascaded_context[0])
1052 return scale_gamma(c, srcSlice, srcStride, srcSliceY, srcSliceH,
1053 dstSlice, dstStride, dstSliceY, dstSliceH);
1054
1055
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
135 if (c->cascaded_context[0] && srcSliceY == 0 && srcSliceH == c->cascaded_context[0]->src_h)
1056 return scale_cascaded(c, srcSlice, srcStride, srcSliceY, srcSliceH,
1057 dstSlice, dstStride, dstSliceY, dstSliceH);
1058
1059
3/8
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
135 if (!srcSliceY && (sws->flags & SWS_BITEXACT) && sws->dither == SWS_DITHER_ED && c->dither_error[0])
1060 for (i = 0; i < 4; i++)
1061 memset(c->dither_error[i], 0, sizeof(c->dither_error[0][0]) * (sws->dst_w+2));
1062
1063
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 135 times.
135 if (usePal(sws->src_format))
1064 ff_update_palette(c, (const uint32_t *)srcSlice[1]);
1065
1066 135 memcpy(src2, srcSlice, sizeof(src2));
1067 135 memcpy(dst2, dstSlice, sizeof(dst2));
1068 135 memcpy(srcStride2, srcStride, sizeof(srcStride2));
1069 135 memcpy(dstStride2, dstStride, sizeof(dstStride2));
1070
1071
3/4
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 53 times.
✓ Branch 2 taken 82 times.
✗ Branch 3 not taken.
135 if (frame_start && !scale_dst) {
1072
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
82 if (srcSliceY != 0 && srcSliceY + srcSliceH != sws->src_h) {
1073 av_log(c, AV_LOG_ERROR, "Slices start in the middle!\n");
1074 return AVERROR(EINVAL);
1075 }
1076
1077
1/2
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
82 c->sliceDir = (srcSliceY == 0) ? 1 : -1;
1078
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 } else if (scale_dst)
1079 c->sliceDir = 1;
1080
1081
4/6
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 125 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
135 if (c->src0Alpha && !c->dst0Alpha && isALPHA(sws->dst_format)) {
1082 uint8_t *base;
1083 int x,y;
1084
1085 av_fast_malloc(&c->rgb0_scratch, &c->rgb0_scratch_allocated,
1086 FFABS(srcStride[0]) * srcSliceH + 32);
1087 if (!c->rgb0_scratch)
1088 return AVERROR(ENOMEM);
1089
1090 base = srcStride[0] < 0 ? c->rgb0_scratch - srcStride[0] * (srcSliceH-1) :
1091 c->rgb0_scratch;
1092 for (y=0; y<srcSliceH; y++){
1093 memcpy(base + srcStride[0]*y, src2[0] + srcStride[0]*y, 4*sws->src_w);
1094 for (x=c->src0Alpha-1; x<4*sws->src_w; x+=4) {
1095 base[ srcStride[0]*y + x] = 0xFF;
1096 }
1097 }
1098 src2[0] = base;
1099 }
1100
1101
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
135 if (c->srcXYZ && !(c->dstXYZ && sws->src_w==sws->dst_w && sws->src_h==sws->dst_h)) {
1102 uint8_t *base;
1103
1104 av_fast_malloc(&c->xyz_scratch, &c->xyz_scratch_allocated,
1105 FFABS(srcStride[0]) * srcSliceH + 32);
1106 if (!c->xyz_scratch)
1107 return AVERROR(ENOMEM);
1108
1109 base = srcStride[0] < 0 ? c->xyz_scratch - srcStride[0] * (srcSliceH-1) :
1110 c->xyz_scratch;
1111
1112 ff_xyz12Torgb48(c, base, srcStride[0], src2[0], srcStride[0], sws->src_w, srcSliceH);
1113 src2[0] = base;
1114 }
1115
1116
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
135 if (c->sliceDir != 1) {
1117 // slices go from bottom to top => we flip the image internally
1118 for (i=0; i<4; i++) {
1119 srcStride2[i] *= -1;
1120 dstStride2[i] *= -1;
1121 }
1122
1123 src2[0] += (srcSliceH - 1) * srcStride[0];
1124 if (!usePal(sws->src_format))
1125 src2[1] += ((srcSliceH >> c->chrSrcVSubSample) - 1) * srcStride[1];
1126 src2[2] += ((srcSliceH >> c->chrSrcVSubSample) - 1) * srcStride[2];
1127 src2[3] += (srcSliceH - 1) * srcStride[3];
1128 dst2[0] += ( sws->dst_h - 1) * dstStride[0];
1129 dst2[1] += ((sws->dst_h >> c->chrDstVSubSample) - 1) * dstStride[1];
1130 dst2[2] += ((sws->dst_h >> c->chrDstVSubSample) - 1) * dstStride[2];
1131 dst2[3] += ( sws->dst_h - 1) * dstStride[3];
1132
1133 srcSliceY_internal = sws->src_h-srcSliceY-srcSliceH;
1134 }
1135 135 reset_ptr(src2, sws->src_format);
1136 135 reset_ptr((void*)dst2, sws->dst_format);
1137
1138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
135 if (c->convert_unscaled) {
1139 int offset = srcSliceY_internal;
1140 int slice_h = srcSliceH;
1141
1142 // for dst slice scaling, offset the pointers to match the unscaled API
1143 if (scale_dst) {
1144 av_assert0(offset == 0);
1145 for (i = 0; i < 4 && src2[i]; i++) {
1146 if (!src2[i] || (i > 0 && usePal(sws->src_format)))
1147 break;
1148 src2[i] += (dstSliceY >> ((i == 1 || i == 2) ? c->chrSrcVSubSample : 0)) * srcStride2[i];
1149 }
1150
1151 for (i = 0; i < 4 && dst2[i]; i++) {
1152 if (!dst2[i] || (i > 0 && usePal(sws->dst_format)))
1153 break;
1154 dst2[i] -= (dstSliceY >> ((i == 1 || i == 2) ? c->chrDstVSubSample : 0)) * dstStride2[i];
1155 }
1156 offset = dstSliceY;
1157 slice_h = dstSliceH;
1158 }
1159
1160 ret = c->convert_unscaled(c, src2, srcStride2, offset, slice_h,
1161 dst2, dstStride2);
1162 if (scale_dst)
1163 dst2[0] += dstSliceY * dstStride2[0];
1164 } else {
1165 135 ret = ff_swscale(c, src2, srcStride2, srcSliceY_internal, srcSliceH,
1166 dst2, dstStride2, dstSliceY, dstSliceH);
1167 }
1168
1169
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
135 if (c->dstXYZ && !(c->srcXYZ && sws->src_w==sws->dst_w && sws->src_h==sws->dst_h)) {
1170 uint8_t *dst;
1171
1172 if (scale_dst) {
1173 dst = dst2[0];
1174 } else {
1175 int dstY = c->dstY ? c->dstY : srcSliceY + srcSliceH;
1176
1177 av_assert0(dstY >= ret);
1178 av_assert0(ret >= 0);
1179 av_assert0(sws->dst_h >= dstY);
1180 dst = dst2[0] + (dstY - ret) * dstStride2[0];
1181 }
1182
1183 /* replace on the same data */
1184 ff_rgb48Toxyz12(c, dst, dstStride2[0], dst, dstStride2[0], sws->dst_w, ret);
1185 }
1186
1187 /* reset slice direction at end of frame */
1188
3/4
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 53 times.
135 if ((srcSliceY_internal + srcSliceH == sws->src_h) || scale_dst)
1189 82 c->sliceDir = 0;
1190
1191 135 return ret;
1192 }
1193
1194 void sws_frame_end(SwsContext *sws)
1195 {
1196 SwsInternal *c = sws_internal(sws);
1197 av_frame_unref(c->frame_src);
1198 av_frame_unref(c->frame_dst);
1199 c->src_ranges.nb_ranges = 0;
1200 }
1201
1202 int sws_frame_start(SwsContext *sws, AVFrame *dst, const AVFrame *src)
1203 {
1204 SwsInternal *c = sws_internal(sws);
1205 int ret, allocated = 0;
1206
1207 ret = av_frame_ref(c->frame_src, src);
1208 if (ret < 0)
1209 return ret;
1210
1211 if (!dst->buf[0]) {
1212 dst->width = sws->dst_w;
1213 dst->height = sws->dst_h;
1214 dst->format = sws->dst_format;
1215
1216 ret = av_frame_get_buffer(dst, 0);
1217 if (ret < 0)
1218 return ret;
1219 allocated = 1;
1220 }
1221
1222 ret = av_frame_ref(c->frame_dst, dst);
1223 if (ret < 0) {
1224 if (allocated)
1225 av_frame_unref(dst);
1226
1227 return ret;
1228 }
1229
1230 return 0;
1231 }
1232
1233 int sws_send_slice(SwsContext *sws, unsigned int slice_start,
1234 unsigned int slice_height)
1235 {
1236 SwsInternal *c = sws_internal(sws);
1237 int ret;
1238
1239 ret = ff_range_add(&c->src_ranges, slice_start, slice_height);
1240 if (ret < 0)
1241 return ret;
1242
1243 return 0;
1244 }
1245
1246 unsigned int sws_receive_slice_alignment(const SwsContext *sws)
1247 {
1248 SwsInternal *c = sws_internal(sws);
1249 if (c->slice_ctx)
1250 return sws_internal(c->slice_ctx[0])->dst_slice_align;
1251
1252 return c->dst_slice_align;
1253 }
1254
1255 int sws_receive_slice(SwsContext *sws, unsigned int slice_start,
1256 unsigned int slice_height)
1257 {
1258 SwsInternal *c = sws_internal(sws);
1259 unsigned int align = sws_receive_slice_alignment(sws);
1260 uint8_t *dst[4];
1261
1262 /* wait until complete input has been received */
1263 if (!(c->src_ranges.nb_ranges == 1 &&
1264 c->src_ranges.ranges[0].start == 0 &&
1265 c->src_ranges.ranges[0].len == sws->src_h))
1266 return AVERROR(EAGAIN);
1267
1268 if ((slice_start > 0 || slice_height < sws->dst_h) &&
1269 (slice_start % align || slice_height % align)) {
1270 av_log(c, AV_LOG_ERROR,
1271 "Incorrectly aligned output: %u/%u not multiples of %u\n",
1272 slice_start, slice_height, align);
1273 return AVERROR(EINVAL);
1274 }
1275
1276 if (c->slicethread) {
1277 int nb_jobs = c->nb_slice_ctx;
1278 int ret = 0;
1279
1280 if (c->slice_ctx[0]->dither == SWS_DITHER_ED)
1281 nb_jobs = 1;
1282
1283 c->dst_slice_start = slice_start;
1284 c->dst_slice_height = slice_height;
1285
1286 avpriv_slicethread_execute(c->slicethread, nb_jobs, 0);
1287
1288 for (int i = 0; i < c->nb_slice_ctx; i++) {
1289 if (c->slice_err[i] < 0) {
1290 ret = c->slice_err[i];
1291 break;
1292 }
1293 }
1294
1295 memset(c->slice_err, 0, c->nb_slice_ctx * sizeof(*c->slice_err));
1296
1297 return ret;
1298 }
1299
1300 for (int i = 0; i < FF_ARRAY_ELEMS(dst); i++) {
1301 ptrdiff_t offset = c->frame_dst->linesize[i] * (ptrdiff_t)(slice_start >> c->chrDstVSubSample);
1302 dst[i] = FF_PTR_ADD(c->frame_dst->data[i], offset);
1303 }
1304
1305 return scale_internal(sws, (const uint8_t * const *)c->frame_src->data,
1306 c->frame_src->linesize, 0, sws->src_h,
1307 dst, c->frame_dst->linesize, slice_start, slice_height);
1308 }
1309
1310 197568 static void get_frame_pointers(const AVFrame *frame, uint8_t *data[4],
1311 int linesize[4], int field)
1312 {
1313
2/2
✓ Branch 0 taken 790272 times.
✓ Branch 1 taken 197568 times.
987840 for (int i = 0; i < 4; i++) {
1314 790272 data[i] = frame->data[i];
1315 790272 linesize[i] = frame->linesize[i];
1316 }
1317
1318
1/2
✓ Branch 0 taken 197568 times.
✗ Branch 1 not taken.
197568 if (!(frame->flags & AV_FRAME_FLAG_INTERLACED)) {
1319 av_assert1(!field);
1320 197568 return;
1321 }
1322
1323 if (field == FIELD_BOTTOM) {
1324 /* Odd rows, offset by one line */
1325 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
1326 for (int i = 0; i < 4; i++) {
1327 data[i] += linesize[i];
1328 if (desc->flags & AV_PIX_FMT_FLAG_PAL)
1329 break;
1330 }
1331 }
1332
1333 /* Take only every second line */
1334 for (int i = 0; i < 4; i++)
1335 linesize[i] <<= 1;
1336 }
1337
1338 /* Subset of av_frame_ref() that only references (video) data buffers */
1339 static int frame_ref(AVFrame *dst, const AVFrame *src)
1340 {
1341 /* ref the buffers */
1342 for (int i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) {
1343 if (!src->buf[i])
1344 continue;
1345 dst->buf[i] = av_buffer_ref(src->buf[i]);
1346 if (!dst->buf[i])
1347 return AVERROR(ENOMEM);
1348 }
1349
1350 memcpy(dst->data, src->data, sizeof(src->data));
1351 memcpy(dst->linesize, src->linesize, sizeof(src->linesize));
1352 return 0;
1353 }
1354
1355 98784 int sws_scale_frame(SwsContext *sws, AVFrame *dst, const AVFrame *src)
1356 {
1357 int ret;
1358 98784 SwsInternal *c = sws_internal(sws);
1359
2/4
✓ Branch 0 taken 98784 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 98784 times.
98784 if (!src || !dst)
1360 return AVERROR(EINVAL);
1361
1362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98784 times.
98784 if (c->frame_src) {
1363 /* Context has been initialized with explicit values, fall back to
1364 * legacy API */
1365 ret = sws_frame_start(sws, dst, src);
1366 if (ret < 0)
1367 return ret;
1368
1369 ret = sws_send_slice(sws, 0, src->height);
1370 if (ret >= 0)
1371 ret = sws_receive_slice(sws, 0, dst->height);
1372
1373 sws_frame_end(sws);
1374
1375 return ret;
1376 }
1377
1378 98784 ret = sws_frame_setup(sws, dst, src);
1379
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98784 times.
98784 if (ret < 0)
1380 return ret;
1381
1382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98784 times.
98784 if (!src->data[0])
1383 return 0;
1384
1385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98784 times.
98784 if (c->graph[FIELD_TOP]->noop &&
1386 (!c->graph[FIELD_BOTTOM] || c->graph[FIELD_BOTTOM]->noop) &&
1387 src->buf[0] && !dst->buf[0] && !dst->data[0])
1388 {
1389 /* Lightweight refcopy */
1390 ret = frame_ref(dst, src);
1391 if (ret < 0)
1392 return ret;
1393 } else {
1394
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98784 times.
98784 if (!dst->data[0]) {
1395 ret = av_frame_get_buffer(dst, 0);
1396 if (ret < 0)
1397 return ret;
1398 }
1399
1400
1/2
✓ Branch 0 taken 98784 times.
✗ Branch 1 not taken.
98784 for (int field = 0; field < 2; field++) {
1401 98784 SwsGraph *graph = c->graph[field];
1402 uint8_t *dst_data[4], *src_data[4];
1403 int dst_linesize[4], src_linesize[4];
1404 98784 get_frame_pointers(dst, dst_data, dst_linesize, field);
1405 98784 get_frame_pointers(src, src_data, src_linesize, field);
1406 98784 ff_sws_graph_run(graph, dst_data, dst_linesize,
1407 (const uint8_t **) src_data, src_linesize);
1408
1/2
✓ Branch 0 taken 98784 times.
✗ Branch 1 not taken.
98784 if (!graph->dst.interlaced)
1409 98784 break;
1410 }
1411 }
1412
1413 98784 return 0;
1414 }
1415
1416 98784 static int validate_params(SwsContext *ctx)
1417 {
1418 #define VALIDATE(field, min, max) \
1419 if (ctx->field < min || ctx->field > max) { \
1420 av_log(ctx, AV_LOG_ERROR, "'%s' (%d) out of range [%d, %d]\n", \
1421 #field, (int) ctx->field, min, max); \
1422 return AVERROR(EINVAL); \
1423 }
1424
1425
2/4
✓ Branch 0 taken 98784 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 98784 times.
98784 VALIDATE(threads, 0, SWS_MAX_THREADS);
1426
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98784 times.
98784 VALIDATE(dither, 0, SWS_DITHER_NB - 1)
1427
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98784 times.
98784 VALIDATE(alpha_blend, 0, SWS_ALPHA_BLEND_NB - 1)
1428 98784 return 0;
1429 }
1430
1431 98784 int sws_frame_setup(SwsContext *ctx, const AVFrame *dst, const AVFrame *src)
1432 {
1433 98784 SwsInternal *s = sws_internal(ctx);
1434 const char *err_msg;
1435 int ret;
1436
1437
2/4
✓ Branch 0 taken 98784 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 98784 times.
98784 if (!src || !dst)
1438 return AVERROR(EINVAL);
1439
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 98784 times.
98784 if ((ret = validate_params(ctx)) < 0)
1440 return ret;
1441
1442
1/2
✓ Branch 0 taken 98784 times.
✗ Branch 1 not taken.
98784 for (int field = 0; field < 2; field++) {
1443 98784 SwsFormat src_fmt = ff_fmt_from_frame(src, field);
1444 98784 SwsFormat dst_fmt = ff_fmt_from_frame(dst, field);
1445 int src_ok, dst_ok;
1446
1447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98784 times.
98784 if ((src->flags ^ dst->flags) & AV_FRAME_FLAG_INTERLACED) {
1448 err_msg = "Cannot convert interlaced to progressive frames or vice versa.\n";
1449 ret = AVERROR(EINVAL);
1450 goto fail;
1451 }
1452
1453 98784 src_ok = ff_test_fmt(&src_fmt, 0);
1454 98784 dst_ok = ff_test_fmt(&dst_fmt, 1);
1455
2/6
✓ Branch 0 taken 98784 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 98784 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
98784 if ((!src_ok || !dst_ok) && !ff_props_equal(&src_fmt, &dst_fmt)) {
1456 err_msg = src_ok ? "Unsupported output" : "Unsupported input";
1457 ret = AVERROR(ENOTSUP);
1458 goto fail;
1459 }
1460
1461 98784 ret = ff_sws_graph_reinit(ctx, &dst_fmt, &src_fmt, field, &s->graph[field]);
1462
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98784 times.
98784 if (ret < 0) {
1463 err_msg = "Failed initializing scaling graph";
1464 goto fail;
1465 }
1466
1467
3/4
✓ Branch 0 taken 98776 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 98776 times.
98784 if (s->graph[field]->incomplete && ctx->flags & SWS_STRICT) {
1468 err_msg = "Incomplete scaling graph";
1469 ret = AVERROR(EINVAL);
1470 goto fail;
1471 }
1472
1473
1/2
✓ Branch 0 taken 98784 times.
✗ Branch 1 not taken.
98784 if (!src_fmt.interlaced) {
1474 98784 ff_sws_graph_free(&s->graph[FIELD_BOTTOM]);
1475 98784 break;
1476 }
1477
1478 continue;
1479
1480 fail:
1481 av_log(ctx, AV_LOG_ERROR, "%s (%s): fmt:%s csp:%s prim:%s trc:%s ->"
1482 " fmt:%s csp:%s prim:%s trc:%s\n",
1483 err_msg, av_err2str(ret),
1484 av_get_pix_fmt_name(src_fmt.format), av_color_space_name(src_fmt.csp),
1485 av_color_primaries_name(src_fmt.color.prim), av_color_transfer_name(src_fmt.color.trc),
1486 av_get_pix_fmt_name(dst_fmt.format), av_color_space_name(dst_fmt.csp),
1487 av_color_primaries_name(dst_fmt.color.prim), av_color_transfer_name(dst_fmt.color.trc));
1488
1489 for (int i = 0; i < FF_ARRAY_ELEMS(s->graph); i++)
1490 ff_sws_graph_free(&s->graph[i]);
1491
1492 return ret;
1493 }
1494
1495 98784 return 0;
1496 }
1497
1498 /**
1499 * swscale wrapper, so we don't need to export the SwsContext.
1500 * Assumes planar YUV to be in YUV order instead of YVU.
1501 */
1502 135 int attribute_align_arg sws_scale(SwsContext *sws,
1503 const uint8_t * const srcSlice[],
1504 const int srcStride[], int srcSliceY,
1505 int srcSliceH, uint8_t *const dst[],
1506 const int dstStride[])
1507 {
1508 135 SwsInternal *c = sws_internal(sws);
1509
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
135 if (c->nb_slice_ctx) {
1510 sws = c->slice_ctx[0];
1511 c = sws_internal(sws);
1512 }
1513
1514 135 return scale_internal(sws, srcSlice, srcStride, srcSliceY, srcSliceH,
1515 dst, dstStride, 0, sws->dst_h);
1516 }
1517
1518 void ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
1519 int nb_jobs, int nb_threads)
1520 {
1521 SwsInternal *parent = priv;
1522 SwsContext *sws = parent->slice_ctx[threadnr];
1523 SwsInternal *c = sws_internal(sws);
1524
1525 const int slice_height = FFALIGN(FFMAX((parent->dst_slice_height + nb_jobs - 1) / nb_jobs, 1),
1526 c->dst_slice_align);
1527 const int slice_start = jobnr * slice_height;
1528 const int slice_end = FFMIN((jobnr + 1) * slice_height, parent->dst_slice_height);
1529 int err = 0;
1530
1531 if (slice_end > slice_start) {
1532 uint8_t *dst[4] = { NULL };
1533
1534 for (int i = 0; i < FF_ARRAY_ELEMS(dst) && parent->frame_dst->data[i]; i++) {
1535 const int vshift = (i == 1 || i == 2) ? c->chrDstVSubSample : 0;
1536 const ptrdiff_t offset = parent->frame_dst->linesize[i] *
1537 (ptrdiff_t)((slice_start + parent->dst_slice_start) >> vshift);
1538
1539 dst[i] = parent->frame_dst->data[i] + offset;
1540 }
1541
1542 err = scale_internal(sws, (const uint8_t * const *)parent->frame_src->data,
1543 parent->frame_src->linesize, 0, sws->src_h,
1544 dst, parent->frame_dst->linesize,
1545 parent->dst_slice_start + slice_start, slice_end - slice_start);
1546 }
1547
1548 parent->slice_err[threadnr] = err;
1549 }
1550