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 |