FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/swscale.c
Date: 2025-01-20 09:27:23
Exec Total Coverage
Lines: 575 839 68.5%
Functions: 30 39 76.9%
Branches: 307 579 53.0%

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 6046854 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 6046854 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
70 int i;
71 6046854 int32_t *dst = (int32_t *) _dst;
72 6046854 const uint16_t *src = (const uint16_t *) _src;
73 6046854 int bits = desc->comp[0].depth - 1;
74 6046854 int sh = bits - 4;
75
76
5/6
✓ Branch 1 taken 3152606 times.
✓ Branch 2 taken 2894248 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3152606 times.
✓ Branch 5 taken 2015038 times.
✓ Branch 6 taken 879210 times.
6046854 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 4608 times.
✓ Branch 1 taken 4027208 times.
4031816 } else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
79 4608 sh = 16 - 1 - 4;
80 }
81
82
2/2
✓ Branch 0 taken 1809529088 times.
✓ Branch 1 taken 6046854 times.
1815575942 for (i = 0; i < dstW; i++) {
83 int j;
84 1809529088 int srcPos = filterPos[i];
85 1809529088 int val = 0;
86
87
2/2
✓ Branch 0 taken 3282093696 times.
✓ Branch 1 taken 1809529088 times.
5091622784 for (j = 0; j < filterSize; j++) {
88 3282093696 val += src[srcPos + j] * filter[filterSize * i + j];
89 }
90 // filter=14 bit, input=16 bit, output=30 bit, >> 11 makes 19 bit
91 1809529088 dst[i] = FFMIN(val >> sh, (1 << 19) - 1);
92 }
93 6046854 }
94
95 27861316 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 27861316 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
100 int i;
101 27861316 const uint16_t *src = (const uint16_t *) _src;
102 27861316 int sh = desc->comp[0].depth - 1;
103
104
2/2
✓ Branch 0 taken 22720406 times.
✓ Branch 1 taken 5140910 times.
27861316 if (sh<15) {
105
4/4
✓ Branch 1 taken 10963857 times.
✓ Branch 2 taken 11756549 times.
✓ Branch 3 taken 10423873 times.
✓ Branch 4 taken 539984 times.
22720406 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 5140910 times.
5140910 } 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 8380052621 times.
✓ Branch 1 taken 27861316 times.
8407913937 for (i = 0; i < dstW; i++) {
111 int j;
112 8380052621 int srcPos = filterPos[i];
113 8380052621 int val = 0;
114
115
2/2
✓ Branch 0 taken 15198010253 times.
✓ Branch 1 taken 8380052621 times.
23578062874 for (j = 0; j < filterSize; j++) {
116 15198010253 val += src[srcPos + j] * filter[filterSize * i + j];
117 }
118 // filter=14 bit, input=16 bit, output=30 bit, >> 15 makes 15 bit
119 8380052621 dst[i] = FFMIN(val >> sh, (1 << 15) - 1);
120 }
121 27861316 }
122
123 // bilinear / bicubic scaling
124 18260531 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 5504453168 times.
✓ Branch 1 taken 18260531 times.
5522713699 for (i = 0; i < dstW; i++) {
130 int j;
131 5504453168 int srcPos = filterPos[i];
132 5504453168 int val = 0;
133
2/2
✓ Branch 0 taken 14211729302 times.
✓ Branch 1 taken 5504453168 times.
19716182470 for (j = 0; j < filterSize; j++) {
134 14211729302 val += ((int)src[srcPos + j]) * filter[filterSize * i + j];
135 }
136 5504453168 dst[i] = FFMIN(val >> 7, (1 << 15) - 1); // the cubic equation does overflow ...
137 }
138 18260531 }
139
140 1889003 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 1889003 int32_t *dst = (int32_t *) _dst;
146
2/2
✓ Branch 0 taken 571506972 times.
✓ Branch 1 taken 1889003 times.
573395975 for (i = 0; i < dstW; i++) {
147 int j;
148 571506972 int srcPos = filterPos[i];
149 571506972 int val = 0;
150
2/2
✓ Branch 0 taken 1055363244 times.
✓ Branch 1 taken 571506972 times.
1626870216 for (j = 0; j < filterSize; j++) {
151 1055363244 val += ((int)src[srcPos + j]) * filter[filterSize * i + j];
152 }
153 571506972 dst[i] = FFMIN(val >> 3, (1 << 19) - 1); // the cubic equation does overflow ...
154 }
155 1889003 }
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 485274 static void chrRangeToJpeg_c(int16_t *dstU, int16_t *dstV, int width,
160 uint32_t _coeff, int64_t _offset)
161 {
162 485274 uint16_t coeff = _coeff;
163 485274 int32_t offset = _offset;
164 int i;
165
2/2
✓ Branch 0 taken 115868488 times.
✓ Branch 1 taken 485274 times.
116353762 for (i = 0; i < width; i++) {
166 115868488 int U = (dstU[i] * coeff + offset) >> 14;
167 115868488 int V = (dstV[i] * coeff + offset) >> 14;
168 115868488 dstU[i] = FFMIN(U, (1 << 15) - 1);
169 115868488 dstV[i] = FFMIN(V, (1 << 15) - 1);
170 }
171 485274 }
172
173 284484 static void chrRangeFromJpeg_c(int16_t *dstU, int16_t *dstV, int width,
174 uint32_t _coeff, int64_t _offset)
175 {
176 284484 uint16_t coeff = _coeff;
177 284484 int32_t offset = _offset;
178 int i;
179
2/2
✓ Branch 0 taken 62619258 times.
✓ Branch 1 taken 284484 times.
62903742 for (i = 0; i < width; i++) {
180 62619258 dstU[i] = (dstU[i] * coeff + offset) >> 14;
181 62619258 dstV[i] = (dstV[i] * coeff + offset) >> 14;
182 }
183 284484 }
184
185 1247417 static void lumRangeToJpeg_c(int16_t *dst, int width,
186 uint32_t _coeff, int64_t _offset)
187 {
188 1247417 uint16_t coeff = _coeff;
189 1247417 int32_t offset = _offset;
190 int i;
191
2/2
✓ Branch 0 taken 430341192 times.
✓ Branch 1 taken 1247417 times.
431588609 for (i = 0; i < width; i++) {
192 430341192 int Y = (dst[i] * coeff + offset) >> 14;
193 430341192 dst[i] = FFMIN(Y, (1 << 15) - 1);
194 }
195 1247417 }
196
197 610848 static void lumRangeFromJpeg_c(int16_t *dst, int width,
198 uint32_t _coeff, int64_t _offset)
199 {
200 610848 uint16_t coeff = _coeff;
201 610848 int32_t offset = _offset;
202 int i;
203
2/2
✓ Branch 0 taken 212264368 times.
✓ Branch 1 taken 610848 times.
212875216 for (i = 0; i < width; i++)
204 212264368 dst[i] = (dst[i] * coeff + offset) >> 14;
205 610848 }
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 205021 static void lumRangeToJpeg16_c(int16_t *_dst, int width,
234 uint32_t coeff, int64_t offset)
235 {
236 int i;
237 205021 int32_t *dst = (int32_t *) _dst;
238
2/2
✓ Branch 0 taken 72099664 times.
✓ Branch 1 taken 205021 times.
72304685 for (i = 0; i < width; i++) {
239 72099664 int Y = ((int64_t) dst[i] * coeff + offset) >> 18;
240 72099664 dst[i] = FFMIN(Y, (1 << 19) - 1);
241 }
242 205021 }
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 406450 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 74877 times.
✓ Branch 1 taken 331573 times.
✓ Branch 2 taken 41464 times.
✓ Branch 3 taken 33413 times.
406450 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 406450 const int dstW = c->opts.dst_w;
268 406450 int dstH = c->opts.dst_h;
269
270 406450 const enum AVPixelFormat dstFormat = c->opts.dst_format;
271 406450 const int flags = c->opts.flags;
272 406450 int32_t *vLumFilterPos = c->vLumFilterPos;
273 406450 int32_t *vChrFilterPos = c->vChrFilterPos;
274
275 406450 const int vLumFilterSize = c->vLumFilterSize;
276 406450 const int vChrFilterSize = c->vChrFilterSize;
277
278 406450 yuv2planar1_fn yuv2plane1 = c->yuv2plane1;
279 406450 yuv2planarX_fn yuv2planeX = c->yuv2planeX;
280 406450 yuv2interleavedX_fn yuv2nv12cX = c->yuv2nv12cX;
281 406450 yuv2packed1_fn yuv2packed1 = c->yuv2packed1;
282 406450 yuv2packed2_fn yuv2packed2 = c->yuv2packed2;
283 406450 yuv2packedX_fn yuv2packedX = c->yuv2packedX;
284 406450 yuv2anyX_fn yuv2anyX = c->yuv2anyX;
285 406450 const int chrSrcSliceY = srcSliceY >> c->chrSrcVSubSample;
286 406450 const int chrSrcSliceH = AV_CEIL_RSHIFT(srcSliceH, c->chrSrcVSubSample);
287
4/4
✓ Branch 1 taken 241359 times.
✓ Branch 2 taken 165091 times.
✓ Branch 3 taken 72959 times.
✓ Branch 4 taken 168400 times.
647809 int should_dither = isNBPS(c->opts.src_format) ||
288 241359 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 406450 int dstY = c->dstY;
293 406450 int lastInLumBuf = c->lastInLumBuf;
294 406450 int lastInChrBuf = c->lastInChrBuf;
295
296 406450 int lumStart = 0;
297 406450 int lumEnd = c->descIndex[0];
298 406450 int chrStart = lumEnd;
299 406450 int chrEnd = c->descIndex[1];
300 406450 int vStart = chrEnd;
301 406450 int vEnd = c->numDesc;
302 406450 SwsSlice *src_slice = &c->slice[lumStart];
303 406450 SwsSlice *hout_slice = &c->slice[c->numSlice-2];
304 406450 SwsSlice *vout_slice = &c->slice[c->numSlice-1];
305 406450 SwsFilterDescriptor *desc = c->desc;
306
307 406450 int needAlpha = c->needAlpha;
308
309 406450 int hasLumHoles = 1;
310 406450 int hasChrHoles = 1;
311
312 const uint8_t *src2[4];
313 int srcStride2[4];
314
315
2/2
✓ Branch 1 taken 95571 times.
✓ Branch 2 taken 310879 times.
406450 if (isPacked(c->opts.src_format)) {
316 95571 src2[0] =
317 95571 src2[1] =
318 95571 src2[2] =
319 95571 src2[3] = src[0];
320 95571 srcStride2[0] =
321 95571 srcStride2[1] =
322 95571 srcStride2[2] =
323 95571 srcStride2[3] = srcStride[0];
324 } else {
325 310879 memcpy(src2, src, sizeof(src2));
326 310879 memcpy(srcStride2, srcStride, sizeof(srcStride2));
327 }
328
329 406450 srcStride2[1] *= 1 << c->vChrDrop;
330 406450 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 401447 times.
✓ Branch 1 taken 5003 times.
✓ Branch 2 taken 391582 times.
✓ Branch 3 taken 9865 times.
406450 if (dstStride[0]&15 || dstStride[1]&15 ||
343
2/4
✓ Branch 0 taken 391582 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 391582 times.
391582 dstStride[2]&15 || dstStride[3]&15) {
344
2/2
✓ Branch 0 taken 8505 times.
✓ Branch 1 taken 6363 times.
14868 SwsInternal *const ctx = c->parent ? sws_internal(c->parent) : c;
345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14868 times.
14868 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 404042 times.
✓ Branch 1 taken 2408 times.
✓ Branch 2 taken 402355 times.
✓ Branch 3 taken 1687 times.
✓ Branch 4 taken 402355 times.
✗ Branch 5 not taken.
406450 if ( (uintptr_t) dst[0]&15 || (uintptr_t) dst[1]&15 || (uintptr_t) dst[2]&15
355
5/6
✓ Branch 0 taken 402340 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 399530 times.
✓ Branch 3 taken 2810 times.
✓ Branch 4 taken 399530 times.
✗ Branch 5 not taken.
402355 || (uintptr_t)src2[0]&15 || (uintptr_t)src2[1]&15 || (uintptr_t)src2[2]&15
356
6/8
✓ Branch 0 taken 396030 times.
✓ Branch 1 taken 3500 times.
✓ Branch 2 taken 388276 times.
✓ Branch 3 taken 7754 times.
✓ Branch 4 taken 388276 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 388276 times.
✗ Branch 7 not taken.
399530 || dstStride[0]&15 || dstStride[1]&15 || dstStride[2]&15 || dstStride[3]&15
357
6/8
✓ Branch 0 taken 388271 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 384525 times.
✓ Branch 3 taken 3746 times.
✓ Branch 4 taken 384525 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 384525 times.
388276 || srcStride2[0]&15 || srcStride2[1]&15 || srcStride2[2]&15 || srcStride2[3]&15
358 ) {
359
2/2
✓ Branch 0 taken 14580 times.
✓ Branch 1 taken 7345 times.
21925 SwsInternal *const ctx = c->parent ? sws_internal(c->parent) : c;
360 21925 int cpu_flags = av_get_cpu_flags();
361
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 21925 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
21925 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 373037 times.
✓ Branch 1 taken 33413 times.
406450 if (scale_dst) {
369 373037 dstY = dstSliceY;
370 373037 dstH = dstY + dstSliceH;
371 373037 lastInLumBuf = -1;
372 373037 lastInChrBuf = -1;
373
2/2
✓ Branch 0 taken 33347 times.
✓ Branch 1 taken 66 times.
33413 } 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 33347 dstY = 0;
378 33347 lastInLumBuf = -1;
379 33347 lastInChrBuf = -1;
380 }
381
382
2/2
✓ Branch 0 taken 168400 times.
✓ Branch 1 taken 238050 times.
406450 if (!should_dither) {
383 168400 c->chrDither8 = c->lumDither8 = sws_pb_64;
384 }
385 406450 lastDstY = dstY;
386
387 406450 ff_init_vscale_pfn(c, yuv2plane1, yuv2planeX, yuv2nv12cX,
388 yuv2packed1, yuv2packed2, yuv2packedX, yuv2anyX, c->use_mmx_vfilter);
389
390 406450 ff_init_slice_from_src(src_slice, (uint8_t**)src2, srcStride2, c->opts.src_w,
391 srcSliceY, srcSliceH, chrSrcSliceY, chrSrcSliceH, 1);
392
393 406450 ff_init_slice_from_src(vout_slice, (uint8_t**)dst, dstStride, c->opts.dst_w,
394 406450 dstY, dstSliceH, dstY >> c->chrDstVSubSample,
395 406450 AV_CEIL_RSHIFT(dstSliceH, c->chrDstVSubSample), scale_dst);
396
2/2
✓ Branch 0 taken 406384 times.
✓ Branch 1 taken 66 times.
406450 if (srcSliceY == 0) {
397 406384 hout_slice->plane[0].sliceY = lastInLumBuf + 1;
398 406384 hout_slice->plane[1].sliceY = lastInChrBuf + 1;
399 406384 hout_slice->plane[2].sliceY = lastInChrBuf + 1;
400 406384 hout_slice->plane[3].sliceY = lastInLumBuf + 1;
401
402 406384 hout_slice->plane[0].sliceH =
403 406384 hout_slice->plane[1].sliceH =
404 406384 hout_slice->plane[2].sliceH =
405 406384 hout_slice->plane[3].sliceH = 0;
406 406384 hout_slice->width = dstW;
407 }
408
409
2/2
✓ Branch 0 taken 22610947 times.
✓ Branch 1 taken 406384 times.
23017331 for (; dstY < dstH; dstY++) {
410 22610947 const int chrDstY = dstY >> c->chrDstVSubSample;
411 22610947 int use_mmx_vfilter= c->use_mmx_vfilter;
412
413 // First line needed as input
414 22610947 const int firstLumSrcY = FFMAX(1 - vLumFilterSize, vLumFilterPos[dstY]);
415
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 22610847 times.
22610947 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 22610947 const int firstChrSrcY = FFMAX(1 - vChrFilterSize, vChrFilterPos[chrDstY]);
418
419 // Last line needed as input
420 22610947 int lastLumSrcY = FFMIN(c->opts.src_h, firstLumSrcY + vLumFilterSize) - 1;
421 22610947 int lastLumSrcY2 = FFMIN(c->opts.src_h, firstLumSrcY2 + vLumFilterSize) - 1;
422 22610947 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 18785465 times.
✓ Branch 1 taken 3825482 times.
22610947 if (firstLumSrcY > lastInLumBuf) {
430
431 18785465 hasLumHoles = lastInLumBuf != firstLumSrcY - 1;
432
2/2
✓ Branch 0 taken 515673 times.
✓ Branch 1 taken 18269792 times.
18785465 if (hasLumHoles) {
433 515673 hout_slice->plane[0].sliceY = firstLumSrcY;
434 515673 hout_slice->plane[3].sliceY = firstLumSrcY;
435 515673 hout_slice->plane[0].sliceH =
436 515673 hout_slice->plane[3].sliceH = 0;
437 }
438
439 18785465 lastInLumBuf = firstLumSrcY - 1;
440 }
441
2/2
✓ Branch 0 taken 9547207 times.
✓ Branch 1 taken 13063740 times.
22610947 if (firstChrSrcY > lastInChrBuf) {
442
443 9547207 hasChrHoles = lastInChrBuf != firstChrSrcY - 1;
444
2/2
✓ Branch 0 taken 652223 times.
✓ Branch 1 taken 8894984 times.
9547207 if (hasChrHoles) {
445 652223 hout_slice->plane[1].sliceY = firstChrSrcY;
446 652223 hout_slice->plane[2].sliceY = firstChrSrcY;
447 652223 hout_slice->plane[1].sliceH =
448 652223 hout_slice->plane[2].sliceH = 0;
449 }
450
451 9547207 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 22610885 times.
✓ Branch 1 taken 62 times.
45221832 enough_lines = lastLumSrcY2 < srcSliceY + srcSliceH &&
462
2/2
✓ Branch 0 taken 22610881 times.
✓ Branch 1 taken 4 times.
22610885 lastChrSrcY < AV_CEIL_RSHIFT(srcSliceY + srcSliceH, c->chrSrcVSubSample);
463
464
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 22610881 times.
22610947 if (!enough_lines) {
465 66 lastLumSrcY = srcSliceY + srcSliceH - 1;
466 66 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 22610947 times.
22610947 av_assert0((lastLumSrcY - firstLumSrcY + 1) <= hout_slice->plane[0].available_lines);
472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22610947 times.
22610947 av_assert0((lastChrSrcY - firstChrSrcY + 1) <= hout_slice->plane[1].available_lines);
473
474
475 22610947 posY = hout_slice->plane[0].sliceY + hout_slice->plane[0].sliceH;
476
4/4
✓ Branch 0 taken 4485023 times.
✓ Branch 1 taken 18125924 times.
✓ Branch 2 taken 3692517 times.
✓ Branch 3 taken 792506 times.
22610947 if (posY <= lastLumSrcY && !hasLumHoles) {
477 3692517 firstPosY = FFMAX(firstLumSrcY, posY);
478
2/2
✓ Branch 0 taken 60429 times.
✓ Branch 1 taken 3632088 times.
3692517 lastPosY = FFMIN(firstLumSrcY + hout_slice->plane[0].available_lines - 1, srcSliceY + srcSliceH - 1);
479 } else {
480 18918430 firstPosY = posY;
481 18918430 lastPosY = lastLumSrcY;
482 }
483
484 22610947 cPosY = hout_slice->plane[1].sliceY + hout_slice->plane[1].sliceH;
485
4/4
✓ Branch 0 taken 4933787 times.
✓ Branch 1 taken 17677160 times.
✓ Branch 2 taken 2718883 times.
✓ Branch 3 taken 2214904 times.
22610947 if (cPosY <= lastChrSrcY && !hasChrHoles) {
486 2718883 firstCPosY = FFMAX(firstChrSrcY, cPosY);
487 2718883 lastCPosY = FFMIN(firstChrSrcY + hout_slice->plane[1].available_lines - 1, AV_CEIL_RSHIFT(srcSliceY + srcSliceH, c->chrSrcVSubSample) - 1);
488 } else {
489 19892064 firstCPosY = cPosY;
490 19892064 lastCPosY = lastChrSrcY;
491 }
492
493 22610947 ff_rotate_slice(hout_slice, lastPosY, lastCPosY);
494
495
2/2
✓ Branch 0 taken 4485023 times.
✓ Branch 1 taken 18125924 times.
22610947 if (posY < lastLumSrcY + 1) {
496
2/2
✓ Branch 0 taken 6392907 times.
✓ Branch 1 taken 4485023 times.
10877930 for (i = lumStart; i < lumEnd; ++i)
497 6392907 desc[i].process(c, &desc[i], firstPosY, lastPosY - firstPosY + 1);
498 }
499
500 22610947 lastInLumBuf = lastLumSrcY;
501
502
2/2
✓ Branch 0 taken 4933787 times.
✓ Branch 1 taken 17677160 times.
22610947 if (cPosY < lastChrSrcY + 1) {
503
2/2
✓ Branch 0 taken 7417831 times.
✓ Branch 1 taken 4933787 times.
12351618 for (i = chrStart; i < chrEnd; ++i)
504 7417831 desc[i].process(c, &desc[i], firstCPosY, lastCPosY - firstCPosY + 1);
505 }
506
507 22610947 lastInChrBuf = lastChrSrcY;
508
509
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 22610881 times.
22610947 if (!enough_lines)
510 66 break; // we can't output a dstY line so let's try with the next slice
511
512 #if HAVE_MMX_INLINE
513 22610881 ff_updateMMXDitherTables(c, dstY);
514 22610881 c->dstW_mmx = c->opts.dst_w;
515 #endif
516
2/2
✓ Branch 0 taken 10381362 times.
✓ Branch 1 taken 12229519 times.
22610881 if (should_dither) {
517 10381362 c->chrDither8 = ff_dither_8x8_128[chrDstY & 7];
518 10381362 c->lumDither8 = ff_dither_8x8_128[dstY & 7];
519 }
520
2/2
✓ Branch 0 taken 149622 times.
✓ Branch 1 taken 22461259 times.
22610881 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 149622 ff_sws_init_output_funcs(c, &yuv2plane1, &yuv2planeX, &yuv2nv12cX,
524 &yuv2packed1, &yuv2packed2, &yuv2packedX, &yuv2anyX);
525 149622 use_mmx_vfilter= 0;
526 149622 ff_init_vscale_pfn(c, yuv2plane1, yuv2planeX, yuv2nv12cX,
527 yuv2packed1, yuv2packed2, yuv2packedX, yuv2anyX, use_mmx_vfilter);
528 }
529
530
2/2
✓ Branch 0 taken 36886861 times.
✓ Branch 1 taken 22610881 times.
59497742 for (i = vStart; i < vEnd; ++i)
531 36886861 desc[i].process(c, &desc[i], dstY, 1);
532 }
533
6/6
✓ Branch 1 taken 289131 times.
✓ Branch 2 taken 117319 times.
✓ Branch 4 taken 8173 times.
✓ Branch 5 taken 280958 times.
✓ Branch 6 taken 6438 times.
✓ Branch 7 taken 1735 times.
406450 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 148 times.
✓ Branch 2 taken 406302 times.
406450 if (av_get_cpu_flags() & AV_CPU_FLAG_MMXEXT)
554 148 __asm__ volatile ("sfence" ::: "memory");
555 #endif
556 406450 emms_c();
557
558 /* store changed local vars back in the context */
559 406450 c->dstY = dstY;
560 406450 c->lastInLumBuf = lastInLumBuf;
561 406450 c->lastInChrBuf = lastInChrBuf;
562
563 406450 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 7598 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 7598 uint16_t src_range = src_max - src_min;
580 7598 uint16_t dst_range = dst_max - dst_min;
581 7598 int total_shift = mult_shift + src_shift;
582 7598 *coeff = AV_CEIL_RSHIFT(((uint64_t) dst_range << total_shift) / src_range, src_shift);
583 7598 *offset = ((int64_t) dst_max << total_shift) -
584 7598 ((int64_t) src_max << src_shift) * *coeff;
585 7598 }
586
587 3799 static void init_range_convert_constants(SwsInternal *c)
588 {
589
2/2
✓ Branch 0 taken 2061 times.
✓ Branch 1 taken 1738 times.
3799 const int bit_depth = c->dstBpc ? c->dstBpc : 8;
590
2/2
✓ Branch 0 taken 3463 times.
✓ Branch 1 taken 336 times.
3799 const int src_bits = bit_depth <= 14 ? 15 : 19;
591 3799 const int src_shift = src_bits - bit_depth;
592
2/2
✓ Branch 0 taken 3463 times.
✓ Branch 1 taken 336 times.
3799 const int mult_shift = bit_depth <= 14 ? 14 : 18;
593 3799 const uint16_t mpeg_min = 16U << (bit_depth - 8);
594 3799 const uint16_t mpeg_max_lum = 235U << (bit_depth - 8);
595 3799 const uint16_t mpeg_max_chr = 240U << (bit_depth - 8);
596 3799 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 948 times.
✓ Branch 1 taken 2851 times.
3799 if (c->opts.src_range) {
600 948 src_min = 0;
601 948 src_max_lum = jpeg_max;
602 948 src_max_chr = jpeg_max;
603 948 dst_min = mpeg_min;
604 948 dst_max_lum = mpeg_max_lum;
605 948 dst_max_chr = mpeg_max_chr;
606 } else {
607 2851 src_min = mpeg_min;
608 2851 src_max_lum = mpeg_max_lum;
609 2851 src_max_chr = mpeg_max_chr;
610 2851 dst_min = 0;
611 2851 dst_max_lum = jpeg_max;
612 2851 dst_max_chr = jpeg_max;
613 }
614 3799 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 3799 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 3799 }
621
622 58704 av_cold void ff_sws_init_range_convert(SwsInternal *c)
623 {
624 58704 c->lumConvertRange = NULL;
625 58704 c->chrConvertRange = NULL;
626
4/4
✓ Branch 0 taken 5073 times.
✓ Branch 1 taken 53631 times.
✓ Branch 3 taken 3799 times.
✓ Branch 4 taken 1274 times.
58704 if (c->opts.src_range != c->opts.dst_range && !isAnyRGB(c->opts.dst_format)) {
627 3799 init_range_convert_constants(c);
628
2/2
✓ Branch 0 taken 3463 times.
✓ Branch 1 taken 336 times.
3799 if (c->dstBpc <= 14) {
629
2/2
✓ Branch 0 taken 902 times.
✓ Branch 1 taken 2561 times.
3463 if (c->opts.src_range) {
630 902 c->lumConvertRange = lumRangeFromJpeg_c;
631 902 c->chrConvertRange = chrRangeFromJpeg_c;
632 } else {
633 2561 c->lumConvertRange = lumRangeToJpeg_c;
634 2561 c->chrConvertRange = chrRangeToJpeg_c;
635 }
636 } else {
637
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 290 times.
336 if (c->opts.src_range) {
638 46 c->lumConvertRange = lumRangeFromJpeg16_c;
639 46 c->chrConvertRange = chrRangeFromJpeg16_c;
640 } else {
641 290 c->lumConvertRange = lumRangeToJpeg16_c;
642 290 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 3799 ff_sws_init_range_convert_x86(c);
654 #endif
655 }
656 58704 }
657
658 33058 static av_cold void sws_init_swscale(SwsInternal *c)
659 {
660 33058 enum AVPixelFormat srcFormat = c->opts.src_format;
661
662 33058 ff_sws_init_output_funcs(c, &c->yuv2plane1, &c->yuv2planeX,
663 &c->yuv2nv12cX, &c->yuv2packed1,
664 &c->yuv2packed2, &c->yuv2packedX, &c->yuv2anyX);
665
666 33058 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 19814 times.
✓ Branch 1 taken 13244 times.
33058 if (c->srcBpc == 8) {
670
2/2
✓ Branch 0 taken 18013 times.
✓ Branch 1 taken 1801 times.
19814 if (c->dstBpc <= 14) {
671 18013 c->hyScale = c->hcScale = hScale8To15_c;
672
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18013 times.
18013 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 1801 c->hyScale = c->hcScale = hScale8To19_c;
678 }
679 } else {
680 13244 c->hyScale = c->hcScale = c->dstBpc > 14 ? hScale16To19_c
681
2/2
✓ Branch 0 taken 2784 times.
✓ Branch 1 taken 10460 times.
13244 : hScale16To15_c;
682 }
683
684 33058 ff_sws_init_range_convert(c);
685
686
8/8
✓ Branch 1 taken 32391 times.
✓ Branch 2 taken 667 times.
✓ Branch 4 taken 31500 times.
✓ Branch 5 taken 891 times.
✓ Branch 6 taken 31418 times.
✓ Branch 7 taken 82 times.
✓ Branch 8 taken 31332 times.
✓ Branch 9 taken 86 times.
33058 if (!(isGray(srcFormat) || isGray(c->opts.dst_format) ||
687 srcFormat == AV_PIX_FMT_MONOBLACK || srcFormat == AV_PIX_FMT_MONOWHITE))
688 31332 c->needs_hcscale = 1;
689 33058 }
690
691 33058 void ff_sws_init_scale(SwsInternal *c)
692 {
693 33058 sws_init_swscale(c);
694
695 #if ARCH_PPC
696 ff_sws_init_swscale_ppc(c);
697 #elif ARCH_X86
698 33058 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 33058 }
709
710 296 static void reset_ptr(const uint8_t *src[], enum AVPixelFormat format)
711 {
712
2/2
✓ Branch 1 taken 262 times.
✓ Branch 2 taken 34 times.
296 if (!isALPHA(format))
713 262 src[3] = NULL;
714
2/2
✓ Branch 1 taken 116 times.
✓ Branch 2 taken 180 times.
296 if (!isPlanar(format)) {
715 116 src[3] = src[2] = NULL;
716
717
1/2
✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
116 if (!usePal(format))
718 116 src[1] = NULL;
719 }
720 296 }
721
722 296 static int check_image_pointers(const uint8_t * const data[4], enum AVPixelFormat pix_fmt,
723 const int linesizes[4])
724 {
725 296 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 1184 times.
✓ Branch 1 taken 296 times.
1480 for (i = 0; i < 4; i++) {
731 1184 int plane = desc->comp[i].plane;
732
2/4
✓ Branch 0 taken 1184 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1184 times.
1184 if (!data[plane] || !linesizes[plane])
733 return 0;
734 }
735
736 296 return 1;
737 }
738
739 1875 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 1875 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
743
744
2/2
✓ Branch 0 taken 60768 times.
✓ Branch 1 taken 1875 times.
62643 for (int yp = 0; yp < h; yp++) {
745 60768 const uint16_t *src16 = (const uint16_t *) src;
746 60768 uint16_t *dst16 = (uint16_t *) dst;
747
748
2/2
✓ Branch 0 taken 21390336 times.
✓ Branch 1 taken 60768 times.
21451104 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 21288960 times.
21390336 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 21288960 x = AV_RL16(src16 + xp + 0);
757 21288960 y = AV_RL16(src16 + xp + 1);
758 21288960 z = AV_RL16(src16 + xp + 2);
759 }
760
761 21390336 x = c->xyzgamma[x >> 4];
762 21390336 y = c->xyzgamma[y >> 4];
763 21390336 z = c->xyzgamma[z >> 4];
764
765 // convert from XYZlinear to sRGBlinear
766 21390336 r = c->xyz2rgb_matrix[0][0] * x +
767 21390336 c->xyz2rgb_matrix[0][1] * y +
768 21390336 c->xyz2rgb_matrix[0][2] * z >> 12;
769 21390336 g = c->xyz2rgb_matrix[1][0] * x +
770 21390336 c->xyz2rgb_matrix[1][1] * y +
771 21390336 c->xyz2rgb_matrix[1][2] * z >> 12;
772 21390336 b = c->xyz2rgb_matrix[2][0] * x +
773 21390336 c->xyz2rgb_matrix[2][1] * y +
774 21390336 c->xyz2rgb_matrix[2][2] * z >> 12;
775
776 // limit values to 16-bit depth
777 21390336 r = av_clip_uint16(r);
778 21390336 g = av_clip_uint16(g);
779 21390336 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 21288960 times.
21390336 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 21288960 AV_WL16(dst16 + xp + 0, c->rgbgamma[r] << 4);
788 21288960 AV_WL16(dst16 + xp + 1, c->rgbgamma[g] << 4);
789 21288960 AV_WL16(dst16 + xp + 2, c->rgbgamma[b] << 4);
790 }
791 }
792
793 60768 src += src_stride;
794 60768 dst += dst_stride;
795 }
796 1875 }
797
798 1916 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 1916 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.dst_format);
802
803
2/2
✓ Branch 0 taken 72200 times.
✓ Branch 1 taken 1916 times.
74116 for (int yp = 0; yp < h; yp++) {
804 72200 uint16_t *src16 = (uint16_t *) src;
805 72200 uint16_t *dst16 = (uint16_t *) dst;
806
807
2/2
✓ Branch 0 taken 25384000 times.
✓ Branch 1 taken 72200 times.
25456200 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 23336480 times.
25384000 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 23336480 r = AV_RL16(src16 + xp + 0);
816 23336480 g = AV_RL16(src16 + xp + 1);
817 23336480 b = AV_RL16(src16 + xp + 2);
818 }
819
820 25384000 r = c->rgbgammainv[r>>4];
821 25384000 g = c->rgbgammainv[g>>4];
822 25384000 b = c->rgbgammainv[b>>4];
823
824 // convert from sRGBlinear to XYZlinear
825 25384000 x = c->rgb2xyz_matrix[0][0] * r +
826 25384000 c->rgb2xyz_matrix[0][1] * g +
827 25384000 c->rgb2xyz_matrix[0][2] * b >> 12;
828 25384000 y = c->rgb2xyz_matrix[1][0] * r +
829 25384000 c->rgb2xyz_matrix[1][1] * g +
830 25384000 c->rgb2xyz_matrix[1][2] * b >> 12;
831 25384000 z = c->rgb2xyz_matrix[2][0] * r +
832 25384000 c->rgb2xyz_matrix[2][1] * g +
833 25384000 c->rgb2xyz_matrix[2][2] * b >> 12;
834
835 // limit values to 16-bit depth
836 25384000 x = av_clip_uint16(x);
837 25384000 y = av_clip_uint16(y);
838 25384000 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 23336480 times.
25384000 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 23336480 AV_WL16(dst16 + xp + 0, c->xyzgammainv[x] << 4);
847 23336480 AV_WL16(dst16 + xp + 1, c->xyzgammainv[y] << 4);
848 23336480 AV_WL16(dst16 + xp + 2, c->xyzgammainv[z] << 4);
849 }
850 }
851
852 72200 src += src_stride;
853 72200 dst += dst_stride;
854 }
855 1916 }
856
857 4585 void ff_update_palette(SwsInternal *c, const uint32_t *pal)
858 {
859
2/2
✓ Branch 0 taken 1173760 times.
✓ Branch 1 taken 4585 times.
1178345 for (int i = 0; i < 256; i++) {
860 1173760 int r, g, b, y, u, v, a = 0xff;
861
2/2
✓ Branch 0 taken 1118464 times.
✓ Branch 1 taken 55296 times.
1173760 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 55040 times.
55296 } 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 54784 times.
55040 } 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 54528 times.
54784 } 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 54272 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 256 times.
54528 } else if (c->opts.src_format == AV_PIX_FMT_GRAY8 || c->opts.src_format == AV_PIX_FMT_GRAY8A) {
880 54272 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 1173760 y = av_clip_uint8((RY * r + GY * g + BY * b + ( 33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
899 1173760 u = av_clip_uint8((RU * r + GU * g + BU * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
900 1173760 v = av_clip_uint8((RV * r + GV * g + BV * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
901 1173760 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 311552 times.
1173760 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 311552 case AV_PIX_FMT_RGB32:
931 #if !HAVE_BIGENDIAN
932 case AV_PIX_FMT_BGR24:
933 #endif
934 default:
935 311552 c->pal_rgb[i]= b + (g<<8) + (r<<16) + ((unsigned)a<<24);
936 }
937 }
938 4585 }
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 148 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 148 SwsInternal *c = sws_internal(sws);
1006
2/4
✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 148 times.
148 const int scale_dst = dstSliceY > 0 || dstSliceH < sws->dst_h;
1007
3/4
✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 82 times.
✓ Branch 3 taken 66 times.
148 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 148 times.
✗ Branch 2 not taken.
148 int macro_height_src = isBayer(sws->src_format) ? 2 : (1 << c->chrSrcVSubSample);
1012
1/2
✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
148 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 148 int srcSliceY_internal = srcSliceY;
1017
1018
4/8
✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 148 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 148 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 148 times.
148 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 148 times.
✗ Branch 1 not taken.
148 if ((srcSliceY & (macro_height_src - 1)) ||
1024
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
148 ((srcSliceH & (macro_height_src - 1)) && srcSliceY + srcSliceH != sws->src_h) ||
1025
2/4
✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 148 times.
296 srcSliceY + srcSliceH > sws->src_h ||
1026
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
148 (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 148 times.
✗ Branch 1 not taken.
148 if ((dstSliceY & (macro_height_dst - 1)) ||
1032
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
148 ((dstSliceH & (macro_height_dst - 1)) && dstSliceY + dstSliceH != sws->dst_h) ||
1033
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
148 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 148 times.
148 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 148 times.
148 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 148 times.
148 if (srcSliceH == 0)
1049 return 0;
1050
1051
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
148 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 148 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
148 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 66 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.
148 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 148 times.
148 if (usePal(sws->src_format))
1064 ff_update_palette(c, (const uint32_t *)srcSlice[1]);
1065
1066 148 memcpy(src2, srcSlice, sizeof(src2));
1067 148 memcpy(dst2, dstSlice, sizeof(dst2));
1068 148 memcpy(srcStride2, srcStride, sizeof(srcStride2));
1069 148 memcpy(dstStride2, dstStride, sizeof(dstStride2));
1070
1071
3/4
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 82 times.
✗ Branch 3 not taken.
148 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 66 times.
66 } else if (scale_dst)
1079 c->sliceDir = 1;
1080
1081
4/6
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
148 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 148 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.
148 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 148 times.
148 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 148 reset_ptr(src2, sws->src_format);
1136 148 reset_ptr((void*)dst2, sws->dst_format);
1137
1138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
148 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 148 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 148 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.
148 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 66 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 66 times.
148 if ((srcSliceY_internal + srcSliceH == sws->src_h) || scale_dst)
1189 82 c->sliceDir = 0;
1190
1191 148 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 168562 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 674248 times.
✓ Branch 1 taken 168562 times.
842810 for (int i = 0; i < 4; i++) {
1314 674248 data[i] = frame->data[i];
1315 674248 linesize[i] = frame->linesize[i];
1316 }
1317
1318
1/2
✓ Branch 0 taken 168562 times.
✗ Branch 1 not taken.
168562 if (!(frame->flags & AV_FRAME_FLAG_INTERLACED)) {
1319 av_assert1(!field);
1320 168562 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 84281 int sws_scale_frame(SwsContext *sws, AVFrame *dst, const AVFrame *src)
1356 {
1357 int ret;
1358 84281 SwsInternal *c = sws_internal(sws);
1359
2/4
✓ Branch 0 taken 84281 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84281 times.
84281 if (!src || !dst)
1360 return AVERROR(EINVAL);
1361
1362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84281 times.
84281 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 84281 ret = sws_frame_setup(sws, dst, src);
1379
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84281 times.
84281 if (ret < 0)
1380 return ret;
1381
1382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84281 times.
84281 if (!src->data[0])
1383 return 0;
1384
1385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84281 times.
84281 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 84281 times.
84281 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 84281 times.
✗ Branch 1 not taken.
84281 for (int field = 0; field < 2; field++) {
1401 84281 SwsGraph *graph = c->graph[field];
1402 uint8_t *dst_data[4], *src_data[4];
1403 int dst_linesize[4], src_linesize[4];
1404 84281 get_frame_pointers(dst, dst_data, dst_linesize, field);
1405 84281 get_frame_pointers(src, src_data, src_linesize, field);
1406 84281 ff_sws_graph_run(graph, dst_data, dst_linesize,
1407 (const uint8_t **) src_data, src_linesize);
1408
1/2
✓ Branch 0 taken 84281 times.
✗ Branch 1 not taken.
84281 if (!graph->dst.interlaced)
1409 84281 break;
1410 }
1411 }
1412
1413 84281 return 0;
1414 }
1415
1416 84281 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 84281 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84281 times.
84281 VALIDATE(threads, 0, SWS_MAX_THREADS);
1426
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84281 times.
84281 VALIDATE(dither, 0, SWS_DITHER_NB - 1)
1427
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84281 times.
84281 VALIDATE(alpha_blend, 0, SWS_ALPHA_BLEND_NB - 1)
1428 84281 return 0;
1429 }
1430
1431 84281 int sws_frame_setup(SwsContext *ctx, const AVFrame *dst, const AVFrame *src)
1432 {
1433 84281 SwsInternal *s = sws_internal(ctx);
1434 const char *err_msg;
1435 int ret;
1436
1437
2/4
✓ Branch 0 taken 84281 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84281 times.
84281 if (!src || !dst)
1438 return AVERROR(EINVAL);
1439
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 84281 times.
84281 if ((ret = validate_params(ctx)) < 0)
1440 return ret;
1441
1442
1/2
✓ Branch 0 taken 84281 times.
✗ Branch 1 not taken.
84281 for (int field = 0; field < 2; field++) {
1443 84281 SwsFormat src_fmt = ff_fmt_from_frame(src, field);
1444 84281 SwsFormat dst_fmt = ff_fmt_from_frame(dst, field);
1445
1446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84281 times.
84281 if ((src->flags ^ dst->flags) & AV_FRAME_FLAG_INTERLACED) {
1447 err_msg = "Cannot convert interlaced to progressive frames or vice versa.\n";
1448 ret = AVERROR(EINVAL);
1449 goto fail;
1450 }
1451
1452
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 84281 times.
84281 if (!ff_test_fmt(&src_fmt, 0)) {
1453 err_msg = "Unsupported input";
1454 ret = AVERROR(ENOTSUP);
1455 goto fail;
1456 }
1457
1458
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 84281 times.
84281 if (!ff_test_fmt(&dst_fmt, 1)) {
1459 err_msg = "Unsupported output";
1460 ret = AVERROR(ENOTSUP);
1461 goto fail;
1462 }
1463
1464 84281 ret = ff_sws_graph_reinit(ctx, &dst_fmt, &src_fmt, field, &s->graph[field]);
1465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84281 times.
84281 if (ret < 0) {
1466 err_msg = "Failed initializing scaling graph";
1467 goto fail;
1468 }
1469
1470
3/4
✓ Branch 0 taken 84273 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84273 times.
84281 if (s->graph[field]->incomplete && ctx->flags & SWS_STRICT) {
1471 err_msg = "Incomplete scaling graph";
1472 ret = AVERROR(EINVAL);
1473 goto fail;
1474 }
1475
1476
1/2
✓ Branch 0 taken 84281 times.
✗ Branch 1 not taken.
84281 if (!src_fmt.interlaced) {
1477 84281 ff_sws_graph_free(&s->graph[FIELD_BOTTOM]);
1478 84281 break;
1479 }
1480
1481 continue;
1482
1483 fail:
1484 av_log(ctx, AV_LOG_ERROR, "%s (%s): fmt:%s csp:%s prim:%s trc:%s ->"
1485 " fmt:%s csp:%s prim:%s trc:%s\n",
1486 err_msg, av_err2str(ret),
1487 av_get_pix_fmt_name(src_fmt.format), av_color_space_name(src_fmt.csp),
1488 av_color_primaries_name(src_fmt.color.prim), av_color_transfer_name(src_fmt.color.trc),
1489 av_get_pix_fmt_name(dst_fmt.format), av_color_space_name(dst_fmt.csp),
1490 av_color_primaries_name(dst_fmt.color.prim), av_color_transfer_name(dst_fmt.color.trc));
1491
1492 for (int i = 0; i < FF_ARRAY_ELEMS(s->graph); i++)
1493 ff_sws_graph_free(&s->graph[i]);
1494
1495 return ret;
1496 }
1497
1498 84281 return 0;
1499 }
1500
1501 /**
1502 * swscale wrapper, so we don't need to export the SwsContext.
1503 * Assumes planar YUV to be in YUV order instead of YVU.
1504 */
1505 148 int attribute_align_arg sws_scale(SwsContext *sws,
1506 const uint8_t * const srcSlice[],
1507 const int srcStride[], int srcSliceY,
1508 int srcSliceH, uint8_t *const dst[],
1509 const int dstStride[])
1510 {
1511 148 SwsInternal *c = sws_internal(sws);
1512
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
148 if (c->nb_slice_ctx) {
1513 sws = c->slice_ctx[0];
1514 c = sws_internal(sws);
1515 }
1516
1517 148 return scale_internal(sws, srcSlice, srcStride, srcSliceY, srcSliceH,
1518 dst, dstStride, 0, sws->dst_h);
1519 }
1520
1521 void ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
1522 int nb_jobs, int nb_threads)
1523 {
1524 SwsInternal *parent = priv;
1525 SwsContext *sws = parent->slice_ctx[threadnr];
1526 SwsInternal *c = sws_internal(sws);
1527
1528 const int slice_height = FFALIGN(FFMAX((parent->dst_slice_height + nb_jobs - 1) / nb_jobs, 1),
1529 c->dst_slice_align);
1530 const int slice_start = jobnr * slice_height;
1531 const int slice_end = FFMIN((jobnr + 1) * slice_height, parent->dst_slice_height);
1532 int err = 0;
1533
1534 if (slice_end > slice_start) {
1535 uint8_t *dst[4] = { NULL };
1536
1537 for (int i = 0; i < FF_ARRAY_ELEMS(dst) && parent->frame_dst->data[i]; i++) {
1538 const int vshift = (i == 1 || i == 2) ? c->chrDstVSubSample : 0;
1539 const ptrdiff_t offset = parent->frame_dst->linesize[i] *
1540 (ptrdiff_t)((slice_start + parent->dst_slice_start) >> vshift);
1541
1542 dst[i] = parent->frame_dst->data[i] + offset;
1543 }
1544
1545 err = scale_internal(sws, (const uint8_t * const *)parent->frame_src->data,
1546 parent->frame_src->linesize, 0, sws->src_h,
1547 dst, parent->frame_dst->linesize,
1548 parent->dst_slice_start + slice_start, slice_end - slice_start);
1549 }
1550
1551 parent->slice_err[threadnr] = err;
1552 }
1553