GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 32.3% 240 / 0 / 742
Functions: 35.0% 14 / 0 / 40
Branches: 20.6% 216 / 0 / 1047

filters/focus.cpp
Line Branch Exec Source
1 // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al.
2 // http://avisynth.nl
3
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
17 // http://www.gnu.org/copyleft/gpl.html .
18 //
19 // Linking Avisynth statically or dynamically with other modules is making a
20 // combined work based on Avisynth. Thus, the terms and conditions of the GNU
21 // General Public License cover the whole combination.
22 //
23 // As a special exception, the copyright holders of Avisynth give you
24 // permission to link Avisynth with independent modules that communicate with
25 // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
26 // terms of these independent modules, and to copy and distribute the
27 // resulting combined work under terms of your choice, provided that
28 // every copy of the combined work is accompanied by a complete copy of
29 // the source code of Avisynth (the version of Avisynth used to produce the
30 // combined work), being distributed under the terms of the GNU General
31 // Public License plus this exception. An independent module is a module
32 // which is not derived from or based on Avisynth, such as 3rd-party filters,
33 // import and export plugins, or graphical user interfaces.
34
35 #include "focus.h"
36 #ifdef INTEL_INTRINSICS
37 #include "intel/focus_sse.h"
38 #include "intel/focus_avx2.h"
39 #endif
40 #include <cmath>
41 #include <vector>
42 #include <avs/alignment.h>
43 #include <avs/minmax.h>
44 #include "../core/internal.h"
45 #include <stdint.h>
46
47
48 /********************************************************************
49 ***** Declare index of new filters for Avisynth's filter engine *****
50 ********************************************************************/
51
52 extern const AVSFunction Focus_filters[] = {
53 { "Blur", BUILTIN_FUNC_PREFIX, "cf[]f[mmx]b", Create_Blur }, // amount [-1.0 - 1.5849625] -- log2(3)
54 { "Sharpen", BUILTIN_FUNC_PREFIX, "cf[]f[mmx]b", Create_Sharpen }, // amount [-1.5849625 - 1.0]
55 { "TemporalSoften", BUILTIN_FUNC_PREFIX, "ciii[scenechange]i[mode]i", TemporalSoften::Create }, // radius, luma_threshold, chroma_threshold
56 { "SpatialSoften", BUILTIN_FUNC_PREFIX, "ciii", SpatialSoften::Create }, // radius, luma_threshold, chroma_threshold
57 { 0 }
58 };
59
60
61
62
63
64 /****************************************
65 *** AdjustFocus helper classes ***
66 *** Originally by Ben R.G. ***
67 *** MMX code by Marc FD ***
68 *** Adaptation and bugfixes sh0dan ***
69 *** Code actually requires ISSE! ***
70 *** Not anymore - pure MMX IanB ***
71 *** Implement boundary proc. IanB ***
72 *** Impl. full 8bit MMX proc. IanB ***
73 ***************************************/
74
75 1 AdjustFocusV::AdjustFocusV(double _amount, PClip _child)
76
2/4
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 6 not taken.
1 : GenericVideoFilter(_child), amountd(pow(2.0, _amount)) {
77 1 half_amount = int(32768 * amountd + 0.5);
78 1 }
79
80 template<typename pixel_t>
81 3 static void af_vertical_c(BYTE* line_buf8, BYTE* dstp8, const int height, const int pitch8, const int width, const int half_amount, int bits_per_pixel) {
82 typedef typename std::conditional < sizeof(pixel_t) == 1, int, int64_t>::type weight_t;
83 // kernel:[(1-1/2^_amount)/2, 1/2^_amount, (1-1/2^_amount)/2]
84 3 weight_t center_weight = half_amount*2; // *2: 16 bit scaled arithmetic, but the converted amount parameter scaled is only 15 bits
85 3 weight_t outer_weight = 32768-half_amount; // (1-1/2^_amount)/2 32768 = 0.5
86 3 int max_pixel_value = (1 << bits_per_pixel) - 1;
87
88 3 pixel_t * dstp = reinterpret_cast<pixel_t *>(dstp8);
89 3 pixel_t * line_buf = reinterpret_cast<pixel_t *>(line_buf8);
90 3 int pitch = pitch8 / sizeof(pixel_t);
91
92
2/4
void af_vertical_c<unsigned char>(unsigned char*, unsigned char*, int, int, int, int, int):
✓ Branch 17 → 3 taken 4 times.
✓ Branch 17 → 18 taken 3 times.
void af_vertical_c<unsigned short>(unsigned char*, unsigned char*, int, int, int, int, int):
✗ Branch 17 → 3 not taken.
✗ Branch 17 → 18 not taken.
7 for (int y = height-1; y>0; --y) {
93
2/4
void af_vertical_c<unsigned char>(unsigned char*, unsigned char*, int, int, int, int, int):
✓ Branch 15 → 4 taken 28 times.
✓ Branch 15 → 16 taken 4 times.
void af_vertical_c<unsigned short>(unsigned char*, unsigned char*, int, int, int, int, int):
✗ Branch 15 → 4 not taken.
✗ Branch 15 → 16 not taken.
32 for (int x = 0; x < width; ++x) {
94 pixel_t a;
95 // Note: ScaledPixelClip is overloaded. With int64_t parameter and uint16_t result works for 16 bit
96 if constexpr(sizeof(pixel_t) == 1)
97
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 28 times.
28 a = ScaledPixelClip((weight_t)(dstp[x] * center_weight + (line_buf[x] + dstp[x+pitch]) * outer_weight));
98 else
99 a = (pixel_t)ScaledPixelClipEx((weight_t)(dstp[x] * center_weight + (line_buf[x] + dstp[x+pitch]) * outer_weight), max_pixel_value);
100 28 line_buf[x] = dstp[x];
101 28 dstp[x] = a;
102 }
103 4 dstp += pitch;
104 }
105
2/4
void af_vertical_c<unsigned char>(unsigned char*, unsigned char*, int, int, int, int, int):
✓ Branch 30 → 19 taken 7 times.
✓ Branch 30 → 31 taken 3 times.
void af_vertical_c<unsigned short>(unsigned char*, unsigned char*, int, int, int, int, int):
✗ Branch 30 → 19 not taken.
✗ Branch 30 → 31 not taken.
10 for (int x = 0; x < width; ++x) { // Last row - map centre as lower
106 if constexpr(sizeof(pixel_t) == 1)
107
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 7 times.
14 dstp[x] = ScaledPixelClip((weight_t)(dstp[x] * center_weight + (line_buf[x] + dstp[x]) * outer_weight));
108 else
109 dstp[x] = (pixel_t)ScaledPixelClipEx((weight_t)(dstp[x] * center_weight + (line_buf[x] + dstp[x]) * outer_weight), max_pixel_value);
110 }
111 3 }
112
113 static void af_vertical_c_float(BYTE* line_buf8, BYTE* dstp8, const int height, const int pitch8, const int width, const float amount) {
114 float *dstp = reinterpret_cast<float *>(dstp8);
115 float *line_buf = reinterpret_cast<float *>(line_buf8);
116 int pitch = pitch8 / sizeof(float);
117
118 const float center_weight = amount;
119 const float outer_weight = (1.0f - amount) / 2.0f;
120
121 for (int y = height-1; y>0; --y) {
122 for (int x = 0; x < width; ++x) {
123 float a = dstp[x] * center_weight + (line_buf[x] + dstp[x+pitch]) * outer_weight;
124 line_buf[x] = dstp[x];
125 dstp[x] = a;
126 }
127 dstp += pitch;
128 }
129 for (int x = 0; x < width; ++x) { // Last row - map centre as lower
130 dstp[x] = dstp[x] * center_weight + (line_buf[x] + dstp[x]) * outer_weight;
131 }
132 }
133
134 template<typename pixel_t>
135 3 static void af_vertical_process(BYTE* line_buf, BYTE* dstp, size_t height, size_t pitch, size_t row_size, int half_amount, int bits_per_pixel, IScriptEnvironment* env) {
136 3 size_t width = row_size / sizeof(pixel_t);
137 // only for 8/16 bit, float separated
138 #ifdef INTEL_INTRINSICS
139
3/6
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 6 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 3 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 3 times.
3 if (sizeof(pixel_t) == 1 && (env->GetCPUFlags() & CPUF_AVX2) && width >= 32) {
140 //pitch of aligned frames is always >= 32 so we'll just process some garbage if width is not mod32
141 af_vertical_avx2(line_buf, dstp, (int)height, (int)pitch, (int)width, half_amount);
142 }
143 else
144
3/6
✓ Branch 10 → 11 taken 3 times.
✗ Branch 10 → 13 not taken.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 3 times.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 3 times.
3 if (sizeof(pixel_t) == 1 && (env->GetCPUFlags() & CPUF_SSE2) && width >= 16) {
145 //pitch of aligned frames is always >= 16 so we'll just process some garbage if width is not mod16
146 af_vertical_sse2(line_buf, dstp, (int)height, (int)pitch, (int)width, half_amount);
147 }
148 else if (sizeof(pixel_t) == 2 && (env->GetCPUFlags() & CPUF_AVX2) && row_size >= 32) {
149 af_vertical_uint16_t_avx2(line_buf, dstp, (int)height, (int)pitch, (int)row_size, half_amount);
150 }
151 else if (sizeof(pixel_t) == 2 && (env->GetCPUFlags() & CPUF_SSE4_1) && row_size >= 16) {
152 af_vertical_uint16_t_sse41(line_buf, dstp, (int)height, (int)pitch, (int)row_size, half_amount);
153 }
154 else if (sizeof(pixel_t) == 2 && (env->GetCPUFlags() & CPUF_SSE2) && row_size >= 16) {
155 af_vertical_uint16_t_sse2(line_buf, dstp, (int)height, (int)pitch, (int)row_size, half_amount);
156 }
157 else
158 #ifdef X86_32
159 if (sizeof(pixel_t) == 1 && (env->GetCPUFlags() & CPUF_MMX) && width >= 8)
160 {
161 size_t mod8_width = width / 8 * 8;
162 af_vertical_mmx(line_buf, dstp, height, pitch, mod8_width, half_amount);
163 if (mod8_width != width) {
164 //yes, this is bad for caching. MMX shouldn't be used these days anyway
165 af_vertical_c<uint8_t>(line_buf, dstp + mod8_width, height, pitch, width - mod8_width, half_amount, bits_per_pixel);
166 }
167 } else
168 #endif
169 #endif
170 {
171 3 af_vertical_c<pixel_t>(line_buf, dstp, (int)height, (int)pitch, (int)width, half_amount, bits_per_pixel);
172 }
173 3 }
174
175 static void af_vertical_process_float(BYTE* line_buf, BYTE* dstp, size_t height, size_t pitch, size_t row_size, double amountd, IScriptEnvironment* env) {
176 size_t width = row_size / sizeof(float);
177 #ifdef INTEL_INTRINSICS
178 if ((env->GetCPUFlags() & CPUF_SSE2) && width >= 16) {
179 //pitch of aligned frames is always >= 16 so we'll just process some garbage if width is not mod16
180 af_vertical_sse2_float(line_buf, dstp, (int)height, (int)pitch, (int)row_size, (float)amountd);
181 }
182 else
183 #endif
184 {
185 af_vertical_c_float(line_buf, dstp, (int)height, (int)pitch, (int)width, (float)amountd);
186 }
187 }
188
189 // --------------------------------
190 // Vertical Blur/Sharpen
191 // --------------------------------
192
193 1 PVideoFrame __stdcall AdjustFocusV::GetFrame(int n, IScriptEnvironment* env)
194 {
195 1 PVideoFrame src = child->GetFrame(n, env);
196
197
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 52 not taken.
1 env->MakeWritable(&src);
198
199
2/4
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 52 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 52 not taken.
1 BYTE* line_buf = reinterpret_cast<BYTE*>(env->Allocate(AlignNumber(src->GetRowSize(), FRAME_ALIGN), FRAME_ALIGN, AVS_POOLED_ALLOC));
200
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 1 time.
1 if (!line_buf) {
201 env->ThrowError("AdjustFocusV: Could not reserve memory.");
202 }
203
204
1/2
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 52 not taken.
1 int pixelsize = vi.ComponentSize();
205
1/2
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 52 not taken.
1 int bits_per_pixel = vi.BitsPerComponent();
206
207
2/4
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 52 not taken.
✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 40 not taken.
1 if (vi.IsPlanar()) {
208 1 const int planesYUV[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A};
209 1 const int planesRGB[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A};
210
2/8
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 51 not taken.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 1 time.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 51 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 20 not taken.
1 const int *planes = vi.IsYUV() || vi.IsYUVA() ? planesYUV : planesRGB;
211
212
2/2
✓ Branch 38 → 22 taken 3 times.
✓ Branch 38 → 39 taken 1 time.
4 for (int cplane = 0; cplane < 3; cplane++) {
213 3 int plane = planes[cplane];
214
1/2
✓ Branch 23 → 24 taken 3 times.
✗ Branch 23 → 51 not taken.
3 BYTE* dstp = src->GetWritePtr(plane);
215
1/2
✓ Branch 25 → 26 taken 3 times.
✗ Branch 25 → 51 not taken.
3 int pitch = src->GetPitch(plane);
216
1/2
✓ Branch 27 → 28 taken 3 times.
✗ Branch 27 → 51 not taken.
3 int row_size = src->GetRowSize(plane);
217
1/2
✓ Branch 29 → 30 taken 3 times.
✗ Branch 29 → 51 not taken.
3 int height = src->GetHeight(plane);
218 3 memcpy(line_buf, dstp, row_size); // First row - map centre as upper
219
220
1/3
✓ Branch 30 → 31 taken 3 times.
✗ Branch 30 → 33 not taken.
✗ Branch 30 → 35 not taken.
3 switch (pixelsize) {
221
1/2
✓ Branch 31 → 32 taken 3 times.
✗ Branch 31 → 51 not taken.
3 case 1: af_vertical_process<uint8_t>(line_buf, dstp, height, pitch, row_size, half_amount, bits_per_pixel, env); break;
222 case 2: af_vertical_process<uint16_t>(line_buf, dstp, height, pitch, row_size, half_amount, bits_per_pixel, env); break;
223 default: // 4: float
224 af_vertical_process_float(line_buf, dstp, height, pitch, row_size, amountd, env); break;
225 }
226 }
227 }
228 else {
229 BYTE* dstp = src->GetWritePtr();
230 int pitch = src->GetPitch();
231 int row_size = vi.RowSize();
232 int height = vi.height;
233 memcpy(line_buf, dstp, row_size); // First row - map centre as upper
234 if (pixelsize == 1)
235 af_vertical_process<uint8_t>(line_buf, dstp, height, pitch, row_size, half_amount, bits_per_pixel, env);
236 else
237 af_vertical_process<uint16_t>(line_buf, dstp, height, pitch, row_size, half_amount, bits_per_pixel, env);
238 }
239
240
1/2
✓ Branch 48 → 49 taken 1 time.
✗ Branch 48 → 52 not taken.
1 env->Free(line_buf);
241 1 return src;
242 }
243
244
245 1 AdjustFocusH::AdjustFocusH(double _amount, PClip _child)
246
2/4
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 6 not taken.
1 : GenericVideoFilter(_child), amountd(pow(2.0, _amount)) {
247 1 half_amount = int(32768 * amountd + 0.5);
248 1 }
249
250
251 // --------------------------------------
252 // Blur/Sharpen Horizontal RGB32 C++ Code
253 // --------------------------------------
254
255 template<typename pixel_t, typename weight_t>
256 static AVS_FORCEINLINE void af_horizontal_rgb32_process_line_c(pixel_t b_left, pixel_t g_left, pixel_t r_left, pixel_t a_left, pixel_t *dstp, size_t width, weight_t center_weight, weight_t outer_weight) {
257 size_t x;
258 for (x = 0; x < width-1; ++x)
259 {
260 pixel_t b = ScaledPixelClip((weight_t)(dstp[x*4+0] * center_weight + (b_left + dstp[x*4+4]) * outer_weight));
261 b_left = dstp[x*4+0];
262 dstp[x*4+0] = b;
263 pixel_t g = ScaledPixelClip((weight_t)(dstp[x*4+1] * center_weight + (g_left + dstp[x*4+5]) * outer_weight));
264 g_left = dstp[x*4+1];
265 dstp[x*4+1] = g;
266 pixel_t r = ScaledPixelClip((weight_t)(dstp[x*4+2] * center_weight + (r_left + dstp[x*4+6]) * outer_weight));
267 r_left = dstp[x*4+2];
268 dstp[x*4+2] = r;
269 pixel_t a = ScaledPixelClip((weight_t)(dstp[x*4+3] * center_weight + (a_left + dstp[x*4+7]) * outer_weight));
270 a_left = dstp[x*4+3];
271 dstp[x*4+3] = a;
272 }
273 dstp[x*4+0] = ScaledPixelClip((weight_t)(dstp[x*4+0] * center_weight + (b_left + dstp[x*4+0]) * outer_weight));
274 dstp[x*4+1] = ScaledPixelClip((weight_t)(dstp[x*4+1] * center_weight + (g_left + dstp[x*4+1]) * outer_weight));
275 dstp[x*4+2] = ScaledPixelClip((weight_t)(dstp[x*4+2] * center_weight + (r_left + dstp[x*4+2]) * outer_weight));
276 dstp[x*4+3] = ScaledPixelClip((weight_t)(dstp[x*4+3] * center_weight + (a_left + dstp[x*4+3]) * outer_weight));
277 }
278
279 template<typename pixel_t>
280 static void af_horizontal_rgb32_64_c(BYTE* dstp8, size_t height, size_t pitch8, size_t width, int half_amount) {
281 typedef typename std::conditional < sizeof(pixel_t) == 1, int, int64_t>::type weight_t;
282 // kernel:[(1-1/2^_amount)/2, 1/2^_amount, (1-1/2^_amount)/2]
283 weight_t center_weight = half_amount*2; // *2: 16 bit scaled arithmetic, but the converted amount parameter scaled is only 15 bits
284 weight_t outer_weight = 32768-half_amount; // (1-1/2^_amount)/2 32768 = 0.5
285
286 pixel_t* dstp = reinterpret_cast<pixel_t *>(dstp8);
287 size_t pitch = pitch8 / sizeof(pixel_t);
288
289 for (size_t y = height; y>0; --y)
290 {
291 pixel_t b_left = dstp[0];
292 pixel_t g_left = dstp[1];
293 pixel_t r_left = dstp[2];
294 pixel_t a_left = dstp[3];
295 af_horizontal_rgb32_process_line_c<pixel_t, weight_t>(b_left, g_left, r_left, a_left, dstp, width, center_weight, outer_weight);
296 dstp += pitch;
297 }
298
299 }
300
301
302 // -------------------------------------
303 // Blur/Sharpen Horizontal YUY2 C++ Code
304 // -------------------------------------
305
306 static void af_horizontal_yuy2_c(BYTE* p, int height, int pitch, int width, int amount) {
307 const int center_weight = amount*2;
308 const int outer_weight = 32768-amount;
309 for (int y0 = height; y0>0; --y0)
310 {
311 BYTE yy = p[0];
312 BYTE uv = p[1];
313 BYTE vu = p[3];
314 int x;
315 for (x = 0; x < width-2; ++x)
316 {
317 BYTE y = ScaledPixelClip(p[x*2+0] * center_weight + (yy + p[x*2+2]) * outer_weight);
318 yy = p[x*2+0];
319 p[x*2+0] = y;
320 BYTE w = ScaledPixelClip(p[x*2+1] * center_weight + (uv + p[x*2+5]) * outer_weight);
321 uv = vu;
322 vu = p[x*2+1];
323 p[x*2+1] = w;
324 }
325 BYTE y = ScaledPixelClip(p[x*2+0] * center_weight + (yy + p[x*2+2]) * outer_weight);
326 yy = p[x*2+0];
327 p[x*2+0] = y;
328 p[x*2+1] = ScaledPixelClip(p[x*2+1] * center_weight + (uv + p[x*2+1]) * outer_weight);
329 p[x*2+2] = ScaledPixelClip(p[x*2+2] * center_weight + (yy + p[x*2+2]) * outer_weight);
330 p[x*2+3] = ScaledPixelClip(p[x*2+3] * center_weight + (vu + p[x*2+3]) * outer_weight);
331
332 p += pitch;
333 }
334 }
335
336
337 // --------------------------------------
338 // Blur/Sharpen Horizontal RGB24 C++ Code
339 // --------------------------------------
340
341 template<typename pixel_t>
342 static void af_horizontal_rgb24_48_c(BYTE* dstp8, int height, int pitch8, int width, int half_amount) {
343 typedef typename std::conditional < sizeof(pixel_t) == 1, int, int64_t>::type weight_t;
344 // kernel:[(1-1/2^_amount)/2, 1/2^_amount, (1-1/2^_amount)/2]
345 weight_t center_weight = half_amount*2; // *2: 16 bit scaled arithmetic, but the converted amount parameter scaled is only 15 bits
346 weight_t outer_weight = 32768-half_amount; // (1-1/2^_amount)/2 32768 = 0.5
347
348 pixel_t *dstp = reinterpret_cast<pixel_t *>(dstp8);
349 int pitch = pitch8 / sizeof(pixel_t);
350 for (int y = height; y>0; --y)
351 {
352 pixel_t bb = dstp[0];
353 pixel_t gg = dstp[1];
354 pixel_t rr = dstp[2];
355 int x;
356 for (x = 0; x < width-1; ++x)
357 {
358 // ScaledPixelClip has 2 overloads: BYTE/uint16_t (int/int64 i)
359 pixel_t b = ScaledPixelClip((weight_t)(dstp[x*3+0] * center_weight + (bb + dstp[x*3+3]) * outer_weight));
360 bb = dstp[x*3+0]; dstp[x*3+0] = b;
361 pixel_t g = ScaledPixelClip((weight_t)(dstp[x*3+1] * center_weight + (gg + dstp[x*3+4]) * outer_weight));
362 gg = dstp[x*3+1]; dstp[x*3+1] = g;
363 pixel_t r = ScaledPixelClip((weight_t)(dstp[x*3+2] * center_weight + (rr + dstp[x*3+5]) * outer_weight));
364 rr = dstp[x*3+2]; dstp[x*3+2] = r;
365 }
366 dstp[x*3+0] = ScaledPixelClip((weight_t)(dstp[x*3+0] * center_weight + (bb + dstp[x*3+0]) * outer_weight));
367 dstp[x*3+1] = ScaledPixelClip((weight_t)(dstp[x*3+1] * center_weight + (gg + dstp[x*3+1]) * outer_weight));
368 dstp[x*3+2] = ScaledPixelClip((weight_t)(dstp[x*3+2] * center_weight + (rr + dstp[x*3+2]) * outer_weight));
369 dstp += pitch;
370 }
371 }
372
373 // -------------------------------------
374 // Blur/Sharpen Horizontal YV12 C++ Code
375 // -------------------------------------
376
377 // for linker reasons these forceinlined functions appear in C, intel sse2 and avx2 source as well
378 template<typename pixel_t>
379 static AVS_FORCEINLINE void af_horizontal_planar_process_line_c(pixel_t left, BYTE *dstp8, size_t row_size, int center_weight, int outer_weight) {
380 size_t x;
381 12 pixel_t* dstp = reinterpret_cast<pixel_t *>(dstp8);
382 typedef typename std::conditional < sizeof(pixel_t) == 1, int, int64_t>::type weight_t; // for calling the right ScaledPixelClip()
383 12 size_t width = row_size / sizeof(pixel_t);
384
2/2
✓ Branch 15 → 4 taken 60 times.
✓ Branch 15 → 16 taken 12 times.
72 for (x = 0; x < width-1; ++x) {
385
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 60 times.
60 pixel_t temp = ScaledPixelClip((weight_t)(dstp[x] * (weight_t)center_weight + (left + dstp[x+1]) * (weight_t)outer_weight));
386 60 left = dstp[x];
387 60 dstp[x] = temp;
388 }
389 // ScaledPixelClip has 2 overloads: BYTE/uint16_t (int/int64 i)
390
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 12 times.
12 dstp[x] = ScaledPixelClip((weight_t)(dstp[x] * (weight_t)center_weight + (left + dstp[x]) * (weight_t)outer_weight));
391 12 }
392
393 static AVS_FORCEINLINE void af_horizontal_planar_process_line_uint16_c(uint16_t left, BYTE *dstp8, size_t row_size, int center_weight, int outer_weight, int bits_per_pixel) {
394 size_t x;
395 typedef uint16_t pixel_t;
396 pixel_t* dstp = reinterpret_cast<pixel_t *>(dstp8);
397 const int max_pixel_value = (1 << bits_per_pixel) - 1; // clamping on 10-12-14-16 bitdepth
398 typedef std::conditional < sizeof(pixel_t) == 1, int, int64_t>::type weight_t; // for calling the right ScaledPixelClip()
399 size_t width = row_size / sizeof(pixel_t);
400 for (x = 0; x < width-1; ++x) {
401 pixel_t temp = (pixel_t)ScaledPixelClipEx((weight_t)(dstp[x] * (weight_t)center_weight + (left + dstp[x+1]) * (weight_t)outer_weight), max_pixel_value);
402 left = dstp[x];
403 dstp[x] = temp;
404 }
405 // ScaledPixelClip has 2 overloads: BYTE/uint16_t (int/int64 i)
406 dstp[x] = ScaledPixelClipEx((weight_t)(dstp[x] * (weight_t)center_weight + (left + dstp[x]) * (weight_t)outer_weight), max_pixel_value);
407 }
408
409 static AVS_FORCEINLINE void af_horizontal_planar_process_line_float_c(float left, float* dstp, size_t row_size, float center_weight, float outer_weight) {
410 size_t x;
411 size_t width = row_size / sizeof(float);
412 for (x = 0; x < width - 1; ++x) {
413 float temp = dstp[x] * center_weight + (left + dstp[x + 1]) * outer_weight;
414 left = dstp[x];
415 dstp[x] = temp;
416 }
417 dstp[x] = dstp[x] * center_weight + (left + dstp[x]) * outer_weight;
418 }
419
420 template<typename pixel_t>
421 3 static void af_horizontal_planar_c(BYTE* dstp8, size_t height, size_t pitch8, size_t row_size, size_t half_amount, int bits_per_pixel)
422 {
423 3 pixel_t* dstp = reinterpret_cast<pixel_t *>(dstp8);
424 3 size_t pitch = pitch8 / sizeof(pixel_t);
425 3 int center_weight = int(half_amount*2);
426 3 int outer_weight = int(32768-half_amount);
427 pixel_t left;
428
2/4
void af_horizontal_planar_c<unsigned char>(unsigned char*, unsigned long, unsigned long, unsigned long, unsigned long, int):
✓ Branch 28 → 3 taken 12 times.
✓ Branch 28 → 29 taken 3 times.
void af_horizontal_planar_c<unsigned short>(unsigned char*, unsigned long, unsigned long, unsigned long, unsigned long, int):
✗ Branch 28 → 3 not taken.
✗ Branch 28 → 29 not taken.
15 for (size_t y = height; y>0; --y) {
429 12 left = dstp[0];
430 if constexpr(sizeof(pixel_t) == 1)
431 12 af_horizontal_planar_process_line_c<pixel_t>(left, (BYTE *)dstp, row_size, center_weight, outer_weight);
432 else
433 af_horizontal_planar_process_line_uint16_c(left, (BYTE *)dstp, row_size, center_weight, outer_weight, bits_per_pixel);
434 12 dstp += pitch;
435 }
436 3 }
437
438 static void af_horizontal_planar_float_c(BYTE* dstp8, size_t height, size_t pitch8, size_t row_size, float amount)
439 {
440 float* dstp = reinterpret_cast<float *>(dstp8);
441 size_t pitch = pitch8 / sizeof(float);
442 float center_weight = amount;
443 float outer_weight = (1.0f - amount) / 2.0f;
444 float left;
445 for (size_t y = height; y>0; --y) {
446 left = dstp[0];
447 af_horizontal_planar_process_line_float_c(left, dstp, row_size, center_weight, outer_weight);
448 dstp += pitch;
449 }
450 }
451
452 1 static void copy_frame(const PVideoFrame &src, PVideoFrame &dst, IScriptEnvironment *env, const int *planes, int plane_count) {
453
2/2
✓ Branch 17 → 3 taken 3 times.
✓ Branch 17 → 18 taken 1 time.
4 for (int p = 0; p < plane_count; p++) {
454 3 int plane = planes[p];
455 3 env->BitBlt(dst->GetWritePtr(plane), dst->GetPitch(plane), src->GetReadPtr(plane),
456 src->GetPitch(plane), src->GetRowSize(plane), src->GetHeight(plane));
457 }
458 1 }
459
460 // ----------------------------------
461 // Blur/Sharpen Horizontal GetFrame()
462 // ----------------------------------
463
464 1 PVideoFrame __stdcall AdjustFocusH::GetFrame(int n, IScriptEnvironment* env)
465 {
466
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 198 not taken.
1 PVideoFrame src = child->GetFrame(n, env);
467
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 196 not taken.
1 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
468
469 1 const int planesYUV[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A};
470 1 const int planesRGB[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A};
471
2/8
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 194 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 9 taken 1 time.
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 194 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 10 not taken.
1 const int *planes = vi.IsYUV() || vi.IsYUVA() ? planesYUV : planesRGB;
472
473
1/2
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 194 not taken.
1 int pixelsize = vi.ComponentSize();
474
475
2/4
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 194 not taken.
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 82 not taken.
1 if (vi.IsPlanar()) {
476
2/4
✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 194 not taken.
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 194 not taken.
1 copy_frame(src, dst, env, planes, vi.NumComponents() ); //planar processing is always in-place
477
1/2
✓ Branch 16 → 17 taken 1 time.
✗ Branch 16 → 194 not taken.
1 int bits_per_pixel = vi.BitsPerComponent();
478
2/2
✓ Branch 81 → 18 taken 3 times.
✓ Branch 81 → 191 taken 1 time.
4 for(int cplane=0;cplane<3;cplane++) {
479 3 int plane = planes[cplane];
480
1/2
✓ Branch 19 → 20 taken 3 times.
✗ Branch 19 → 194 not taken.
3 int row_size = dst->GetRowSize(plane);
481
1/2
✓ Branch 21 → 22 taken 3 times.
✗ Branch 21 → 194 not taken.
3 BYTE* q = dst->GetWritePtr(plane);
482
1/2
✓ Branch 23 → 24 taken 3 times.
✗ Branch 23 → 194 not taken.
3 int pitch = dst->GetPitch(plane);
483
1/2
✓ Branch 25 → 26 taken 3 times.
✗ Branch 25 → 194 not taken.
3 int height = dst->GetHeight(plane);
484 #ifdef INTEL_INTRINSICS
485
5/10
✓ Branch 26 → 27 taken 3 times.
✗ Branch 26 → 31 not taken.
✓ Branch 27 → 28 taken 3 times.
✗ Branch 27 → 194 not taken.
✓ Branch 28 → 29 taken 3 times.
✗ Branch 28 → 31 not taken.
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 3 times.
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 34 taken 3 times.
3 if (pixelsize == 1 && (env->GetCPUFlags() & CPUF_AVX2) && row_size > 32) {
486 af_horizontal_planar_avx2(q, height, pitch, row_size, half_amount);
487 }
488 else
489
5/10
✓ Branch 34 → 35 taken 3 times.
✗ Branch 34 → 39 not taken.
✓ Branch 35 → 36 taken 3 times.
✗ Branch 35 → 194 not taken.
✓ Branch 36 → 37 taken 3 times.
✗ Branch 36 → 39 not taken.
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 3 times.
✗ Branch 40 → 41 not taken.
✓ Branch 40 → 42 taken 3 times.
3 if (pixelsize==1 && (env->GetCPUFlags() & CPUF_SSE2) && row_size > 16) {
490 af_horizontal_planar_sse2(q, height, pitch, row_size, half_amount);
491 } else
492 #ifdef X86_32
493 if (pixelsize == 1 && (env->GetCPUFlags() & CPUF_MMX) && row_size > 8) {
494 af_horizontal_planar_mmx(q,height,pitch,row_size,half_amount);
495 } else
496 #endif
497
2/10
✗ Branch 42 → 43 not taken.
✓ Branch 42 → 47 taken 3 times.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 194 not taken.
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 47 not taken.
✗ Branch 45 → 46 not taken.
✗ Branch 45 → 47 not taken.
✗ Branch 48 → 49 not taken.
✓ Branch 48 → 50 taken 3 times.
3 if (pixelsize == 2 && (env->GetCPUFlags() & CPUF_AVX2) && row_size > 32) {
498 af_horizontal_planar_uint16_t_avx2(q, height, pitch, row_size, half_amount, bits_per_pixel);
499 }
500
2/10
✗ Branch 50 → 51 not taken.
✓ Branch 50 → 55 taken 3 times.
✗ Branch 51 → 52 not taken.
✗ Branch 51 → 194 not taken.
✗ Branch 52 → 53 not taken.
✗ Branch 52 → 55 not taken.
✗ Branch 53 → 54 not taken.
✗ Branch 53 → 55 not taken.
✗ Branch 56 → 57 not taken.
✓ Branch 56 → 58 taken 3 times.
3 else if (pixelsize == 2 && (env->GetCPUFlags() & CPUF_SSE4_1) && row_size > 16) {
501 af_horizontal_planar_uint16_t_sse41(q, height, pitch, row_size, half_amount, bits_per_pixel);
502 }
503
2/10
✗ Branch 58 → 59 not taken.
✓ Branch 58 → 63 taken 3 times.
✗ Branch 59 → 60 not taken.
✗ Branch 59 → 194 not taken.
✗ Branch 60 → 61 not taken.
✗ Branch 60 → 63 not taken.
✗ Branch 61 → 62 not taken.
✗ Branch 61 → 63 not taken.
✗ Branch 64 → 65 not taken.
✓ Branch 64 → 66 taken 3 times.
3 else if (pixelsize == 2 && (env->GetCPUFlags() & CPUF_SSE2) && row_size > 16) {
504 af_horizontal_planar_uint16_t_sse2(q, height, pitch, row_size, half_amount, bits_per_pixel);
505 }
506
2/10
✗ Branch 66 → 67 not taken.
✓ Branch 66 → 71 taken 3 times.
✗ Branch 67 → 68 not taken.
✗ Branch 67 → 194 not taken.
✗ Branch 68 → 69 not taken.
✗ Branch 68 → 71 not taken.
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 71 not taken.
✗ Branch 72 → 73 not taken.
✓ Branch 72 → 74 taken 3 times.
3 else if (pixelsize == 4 && (env->GetCPUFlags() & CPUF_SSE2) && row_size > 16) {
507 af_horizontal_planar_float_sse2(q, height, pitch, row_size, (float)amountd);
508 }
509 else
510 #endif
511 {
512
1/3
✓ Branch 74 → 75 taken 3 times.
✗ Branch 74 → 77 not taken.
✗ Branch 74 → 79 not taken.
3 switch (pixelsize) {
513
1/2
✓ Branch 75 → 76 taken 3 times.
✗ Branch 75 → 194 not taken.
3 case 1: af_horizontal_planar_c<uint8_t>(q, height, pitch, row_size, half_amount, bits_per_pixel); break;
514 case 2: af_horizontal_planar_c<uint16_t>(q, height, pitch, row_size, half_amount, bits_per_pixel); break;
515 default: // 4: float
516 af_horizontal_planar_float_c(q, height, pitch, row_size, (float)amountd); break;
517 }
518 }
519 }
520 } else {
521 if (vi.IsYUY2()) {
522 BYTE* q = dst->GetWritePtr();
523 const int pitch = dst->GetPitch();
524 #ifdef INTEL_INTRINSICS
525 if ((env->GetCPUFlags() & CPUF_SSE2) && vi.width>8) {
526 af_horizontal_yuy2_sse2(dst->GetWritePtr(), src->GetReadPtr(), dst->GetPitch(), src->GetPitch(), vi.height, vi.width, half_amount);
527 } else
528 #ifdef X86_32
529 if ((env->GetCPUFlags() & CPUF_MMX) && vi.width>8) {
530 af_horizontal_yuy2_mmx(dst->GetWritePtr(), src->GetReadPtr(), dst->GetPitch(), src->GetPitch(), vi.height, vi.width, half_amount);
531 } else
532 #endif
533 #endif
534 {
535 copy_frame(src, dst, env, planesYUV, 1); //in-place
536 af_horizontal_yuy2_c(q,vi.height,pitch,vi.width,half_amount);
537 }
538 }
539 else if (vi.IsRGB32() || vi.IsRGB64()) {
540 #ifdef INTEL_INTRINSICS
541 if ((pixelsize==1) && (env->GetCPUFlags() & CPUF_SSE2) && vi.width>4) {
542 //this one is NOT in-place
543 af_horizontal_rgb32_sse2(dst->GetWritePtr(), src->GetReadPtr(), dst->GetPitch(), src->GetPitch(), vi.height, vi.width, half_amount);
544 }
545 else if ((pixelsize == 2) && (env->GetCPUFlags() & CPUF_SSE4_1) && vi.width > 2) {
546 //this one is NOT in-place
547 af_horizontal_rgb64_sse41(dst->GetWritePtr(), src->GetReadPtr(), dst->GetPitch(), src->GetPitch(), vi.height, vi.width, half_amount); // really width
548 }
549 else if ((pixelsize == 2) && (env->GetCPUFlags() & CPUF_SSE2) && vi.width > 2) {
550 //this one is NOT in-place
551 af_horizontal_rgb64_sse2(dst->GetWritePtr(), src->GetReadPtr(), dst->GetPitch(), src->GetPitch(), vi.height, vi.width, half_amount); // really width
552 }
553 else
554 #ifdef X86_32
555 if ((pixelsize==1) && (env->GetCPUFlags() & CPUF_MMX) && vi.width > 2)
556 { //so as this one
557 af_horizontal_rgb32_mmx(dst->GetWritePtr(), src->GetReadPtr(), dst->GetPitch(), src->GetPitch(), vi.height, vi.width, half_amount);
558 } else
559 #endif
560 #endif
561 {
562 copy_frame(src, dst, env, planesYUV, 1);
563 if(pixelsize==1)
564 af_horizontal_rgb32_64_c<uint8_t>(dst->GetWritePtr(), vi.height, dst->GetPitch(), vi.width, half_amount);
565 else
566 af_horizontal_rgb32_64_c<uint16_t>(dst->GetWritePtr(), vi.height, dst->GetPitch(), vi.width, half_amount);
567 }
568 } else if (vi.IsRGB24() || vi.IsRGB48()) {
569 copy_frame(src, dst, env, planesYUV, 1);
570 if(pixelsize==1)
571 af_horizontal_rgb24_48_c<uint8_t>(dst->GetWritePtr(), vi.height, dst->GetPitch(), vi.width, half_amount);
572 else
573 af_horizontal_rgb24_48_c<uint16_t>(dst->GetWritePtr(), vi.height, dst->GetPitch(), vi.width, half_amount);
574 }
575 }
576
577 1 return dst;
578 1 }
579
580
581 /************************************************
582 ******* Sharpen/Blur Factory Methods *******
583 ***********************************************/
584
585 AVSValue __cdecl Create_Sharpen(AVSValue args, void*, IScriptEnvironment* env)
586 {
587 const double amountH = args[1].AsFloat(), amountV = args[2].AsDblDef(amountH);
588
589 if (amountH < -1.5849625 || amountH > 1.0 || amountV < -1.5849625 || amountV > 1.0) // log2(3)
590 env->ThrowError("Sharpen: arguments must be in the range -1.58 to 1.0");
591
592 if (fabs(amountH) < 0.00002201361136) { // log2(1+1/65536)
593 if (fabs(amountV) < 0.00002201361136) {
594 return args[0].AsClip();
595 }
596 else {
597 return new AdjustFocusV(amountV, args[0].AsClip());
598 }
599 }
600 else {
601 if (fabs(amountV) < 0.00002201361136) {
602 return new AdjustFocusH(amountH, args[0].AsClip());
603 }
604 else {
605 return new AdjustFocusH(amountH, new AdjustFocusV(amountV, args[0].AsClip()));
606 }
607 }
608 }
609
610 AVSValue __cdecl Create_Blur(AVSValue args, void*, IScriptEnvironment* env)
611 {
612 const double amountH = args[1].AsFloat(), amountV = args[2].AsDblDef(amountH);
613
614 if (amountH < -1.0 || amountH > 1.5849625 || amountV < -1.0 || amountV > 1.5849625) // log2(3)
615 env->ThrowError("Blur: arguments must be in the range -1.0 to 1.58");
616
617 if (fabs(amountH) < 0.00002201361136) { // log2(1+1/65536)
618 if (fabs(amountV) < 0.00002201361136) {
619 return args[0].AsClip();
620 }
621 else {
622 return new AdjustFocusV(-amountV, args[0].AsClip());
623 }
624 }
625 else {
626 if (fabs(amountV) < 0.00002201361136) {
627 return new AdjustFocusH(-amountH, args[0].AsClip());
628 }
629 else {
630 return new AdjustFocusH(-amountH, new AdjustFocusV(-amountV, args[0].AsClip()));
631 }
632 }
633 }
634
635
636
637
638 /***************************
639 **** TemporalSoften *****
640 **************************/
641
642 4 TemporalSoften::TemporalSoften( PClip _child, unsigned radius, unsigned luma_thresh,
643 4 unsigned chroma_thresh, int _scenechange, IScriptEnvironment* env )
644 : GenericVideoFilter(_child),
645 4 scenechange(_scenechange),
646
1/2
✓ Branch 10 → 11 taken 4 times.
✗ Branch 10 → 12 not taken.
4 luma_threshold(min(luma_thresh, 255u)),
647
1/2
✓ Branch 15 → 16 taken 4 times.
✗ Branch 15 → 17 not taken.
4 chroma_threshold(min(chroma_thresh, 255u)),
648
4/6
✓ Branch 2 → 3 taken 4 times.
✗ Branch 2 → 89 not taken.
✓ Branch 3 → 4 taken 4 times.
✗ Branch 3 → 87 not taken.
✓ Branch 5 → 6 taken 3 times.
✓ Branch 5 → 7 taken 1 time.
4 kernel(2 * min(radius, (unsigned int)MAX_RADIUS) + 1)
649 {
650
651
1/2
✓ Branch 21 → 22 taken 4 times.
✗ Branch 21 → 90 not taken.
4 child->SetCacheHints(CACHE_WINDOW,kernel);
652
653
5/10
✓ Branch 22 → 23 taken 4 times.
✗ Branch 22 → 90 not taken.
✓ Branch 23 → 24 taken 4 times.
✗ Branch 23 → 26 not taken.
✓ Branch 24 → 25 taken 4 times.
✗ Branch 24 → 90 not taken.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 4 times.
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 30 taken 4 times.
4 if (vi.IsRGB24() || vi.IsRGB48()) {
654 env->ThrowError("TemporalSoften: RGB24/48 Not supported, use ConvertToRGB32/48().");
655 }
656
657
5/12
✓ Branch 30 → 31 taken 4 times.
✗ Branch 30 → 90 not taken.
✓ Branch 31 → 32 taken 4 times.
✗ Branch 31 → 34 not taken.
✓ Branch 32 → 33 taken 4 times.
✗ Branch 32 → 90 not taken.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 36 taken 4 times.
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 36 not taken.
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 4 times.
4 if ((vi.IsRGB32() || vi.IsRGB64()) && (vi.width&1)) {
658 env->ThrowError("TemporalSoften: RGB32/64 source must be multiple of 2 in width.");
659 }
660
661
3/8
✓ Branch 39 → 40 taken 4 times.
✗ Branch 39 → 90 not taken.
✗ Branch 40 → 41 not taken.
✓ Branch 40 → 43 taken 4 times.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
✗ Branch 44 → 45 not taken.
✓ Branch 44 → 46 taken 4 times.
4 if ((vi.IsYUY2()) && (vi.width&3)) {
662 env->ThrowError("TemporalSoften: YUY2 source must be multiple of 4 in width.");
663 }
664
665
1/2
✗ Branch 46 → 47 not taken.
✓ Branch 46 → 48 taken 4 times.
4 if (scenechange >= 255) {
666 scenechange = 0;
667 }
668
669
2/12
✗ Branch 48 → 49 not taken.
✓ Branch 48 → 54 taken 4 times.
✗ Branch 49 → 50 not taken.
✗ Branch 49 → 90 not taken.
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 53 not taken.
✗ Branch 51 → 52 not taken.
✗ Branch 51 → 90 not taken.
✗ Branch 52 → 53 not taken.
✗ Branch 52 → 54 not taken.
✗ Branch 55 → 56 not taken.
✓ Branch 55 → 57 taken 4 times.
4 if (scenechange>0 && (vi.IsRGB32() || vi.IsRGB64())) {
670 env->ThrowError("TemporalSoften: Scenechange not available on RGB32/64");
671 }
672
673
1/2
✓ Branch 57 → 58 taken 4 times.
✗ Branch 57 → 90 not taken.
4 pixelsize = vi.ComponentSize();
674
1/2
✓ Branch 58 → 59 taken 4 times.
✗ Branch 58 → 90 not taken.
4 bits_per_pixel = vi.BitsPerComponent();
675
676 // original scenechange parameter always 0-255
677 int factor;
678
2/4
✓ Branch 59 → 60 taken 4 times.
✗ Branch 59 → 90 not taken.
✓ Branch 60 → 61 taken 4 times.
✗ Branch 60 → 62 not taken.
4 if (vi.IsPlanar()) // Y/YUV, no Planar RGB here
679 4 factor = 1; // bitdepth independent. sad normalizes
680 else
681 factor = vi.BytesFromPixels(1) / pixelsize; // /pixelsize: correction for packed 16 bit rgb
682 4 scenechange *= ((vi.width/32)*32)*vi.height*factor; // why /*32?
683
684
685 4 int c = 0;
686
5/14
✓ Branch 64 → 65 taken 4 times.
✗ Branch 64 → 90 not taken.
✓ Branch 65 → 66 taken 4 times.
✗ Branch 65 → 71 not taken.
✓ Branch 66 → 67 taken 4 times.
✗ Branch 66 → 90 not taken.
✗ Branch 67 → 68 not taken.
✓ Branch 67 → 70 taken 4 times.
✗ Branch 68 → 69 not taken.
✗ Branch 68 → 90 not taken.
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 71 not taken.
✓ Branch 72 → 73 taken 4 times.
✗ Branch 72 → 77 not taken.
4 if (vi.IsPlanar() && (vi.IsYUV() || vi.IsYUVA())) {
687
1/2
✓ Branch 73 → 74 taken 4 times.
✗ Branch 73 → 75 not taken.
4 if (luma_thresh>0) {
688 4 planes[c].planeId = PLANAR_Y;
689 4 planes[c++].threshold = luma_thresh;
690 }
691
2/2
✓ Branch 75 → 76 taken 3 times.
✓ Branch 75 → 86 taken 1 time.
4 if (chroma_thresh>0) {
692 3 planes[c].planeId = PLANAR_V;
693 3 planes[c++].threshold =chroma_thresh;
694 3 planes[c].planeId = PLANAR_U;
695 3 planes[c++].threshold = chroma_thresh;
696 }
697 } else if (vi.IsYUY2()) {
698 planes[c].planeId=0;
699 planes[c++].threshold=luma_thresh|(chroma_thresh<<8);
700 } else if (vi.IsRGB()) { // For RGB We use Luma.
701 if (vi.IsPlanar()) {
702 planes[c].planeId = PLANAR_G;
703 planes[c++].threshold = luma_thresh;
704 planes[c].planeId = PLANAR_B;
705 planes[c++].threshold = luma_thresh;
706 planes[c].planeId = PLANAR_R;
707 planes[c++].threshold = luma_thresh;
708 }
709 else { // packed RGB
710 planes[c].planeId = 0;
711 planes[c++].threshold = luma_thresh;
712 }
713 }
714 4 planes[c].planeId=0;
715 4 }
716
717 //offset is the initial value of x. Used when C routine processes only parts of frames after SSE/MMX paths do their job.
718 template<typename pixel_t, bool maxThreshold>
719 9 static void accumulate_line_c(BYTE* _c_plane, const BYTE** planeP, int planes, int offset, size_t rowsize, BYTE _threshold, int div, int bits_per_pixel) {
720 9 pixel_t *c_plane = reinterpret_cast<pixel_t *>(_c_plane);
721
722 typedef typename std::conditional < sizeof(pixel_t) <= 2, int, float>::type sum_t;
723 typedef typename std::conditional < sizeof(pixel_t) == 1, int, int64_t>::type bigsum_t;
724 typedef typename std::conditional < std::is_floating_point<pixel_t>::value, float, int>::type threshold_t;
725
726 9 size_t width = rowsize / sizeof(pixel_t);
727
728 9 threshold_t threshold = _threshold; // parameter 0..255
729 if (std::is_floating_point<pixel_t>::value)
730 9 threshold = (threshold_t)(threshold / 255.0f); // float
731 else if constexpr(sizeof(pixel_t) == 2) {
732 threshold = threshold * (uint16_t)(1 << (bits_per_pixel - 8)); // uint16_t, 10 bit: *4 16bit: *256
733 }
734
735 9 float average_multiplier = 0.0f;
736 if constexpr(sizeof(pixel_t) == 2) {
737 // Match the 16-bit SSE paths' float reciprocal and default nearest rounding.
738 average_multiplier = 1.0f / static_cast<float>(planes + 1);
739 }
740
741
2/12
void accumulate_line_c<float, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✓ Branch 15 → 5 taken 144 times.
✓ Branch 15 → 16 taken 9 times.
void accumulate_line_c<float, true>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 12 → 5 not taken.
✗ Branch 12 → 13 not taken.
void accumulate_line_c<unsigned char, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 12 → 4 not taken.
✗ Branch 12 → 13 not taken.
void accumulate_line_c<unsigned char, true>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 10 → 4 not taken.
✗ Branch 10 → 11 not taken.
void accumulate_line_c<unsigned short, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 12 → 4 not taken.
✗ Branch 12 → 13 not taken.
void accumulate_line_c<unsigned short, true>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 10 → 4 not taken.
✗ Branch 10 → 11 not taken.
153 for (size_t x = offset; x < width; ++x) {
742 144 pixel_t current = c_plane[x];
743 144 sum_t sum = current;
744
745
2/12
void accumulate_line_c<float, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✓ Branch 12 → 6 taken 288 times.
✓ Branch 12 → 13 taken 144 times.
void accumulate_line_c<float, true>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void accumulate_line_c<unsigned char, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 10 → 5 not taken.
✗ Branch 10 → 11 not taken.
void accumulate_line_c<unsigned char, true>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 8 → 5 not taken.
✗ Branch 8 → 9 not taken.
void accumulate_line_c<unsigned short, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 10 → 5 not taken.
✗ Branch 10 → 11 not taken.
void accumulate_line_c<unsigned short, true>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 8 → 5 not taken.
✗ Branch 8 → 9 not taken.
432 for (int plane = planes - 1; plane >= 0; plane--) {
746 288 pixel_t p = reinterpret_cast<const pixel_t *>(planeP[plane])[x];
747 if (maxThreshold) {
748 sum += p; // simple frame average mode
749 }
750 else {
751 288 sum_t absdiff = std::abs(current - p);
752
753
2/6
void accumulate_line_c<float, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✓ Branch 8 → 9 taken 151 times.
✓ Branch 8 → 10 taken 137 times.
void accumulate_line_c<unsigned char, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
void accumulate_line_c<unsigned short, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
288 if (absdiff <= threshold) {
754 151 sum += p;
755 }
756 else {
757 137 sum += current;
758 }
759 }
760 }
761 if (std::is_floating_point<pixel_t>::value)
762 144 c_plane[x] = (pixel_t)(sum / (planes + 1)); // float: simple average
763 else if constexpr(sizeof(pixel_t) == 2)
764 c_plane[x] = (pixel_t)std::nearbyintf(static_cast<float>(sum) * average_multiplier);
765 else
766 c_plane[x] = (pixel_t)(((bigsum_t)sum * div + 16384) >> 15); // div = 32768/(planes+1) for integer arithmetic
767 }
768 9 }
769
770 static void accumulate_line_yuy2_c(BYTE* c_plane, const BYTE** planeP, int planes, size_t width, BYTE threshold_luma, BYTE threshold_chroma, int div) {
771 for (size_t x = 0; x < width; x+=2) {
772 BYTE current_y = c_plane[x];
773 BYTE current_c = c_plane[x+1];
774 size_t sum_y = current_y;
775 size_t sum_c = current_c;
776
777 for (int plane = planes - 1; plane >= 0; plane--) {
778 BYTE p_y = planeP[plane][x];
779 BYTE p_c = planeP[plane][x+1];
780 size_t absdiff_y = std::abs(current_y - p_y);
781 size_t absdiff_c = std::abs(current_c - p_c);
782
783 if (absdiff_y <= threshold_luma) {
784 sum_y += p_y;
785 } else {
786 sum_y += current_y;
787 }
788
789 if (absdiff_c <= threshold_chroma) {
790 sum_c += p_c;
791 } else {
792 sum_c += current_c;
793 }
794 }
795
796 c_plane[x] = (BYTE)((sum_y * div + 16384) >> 15);
797 c_plane[x+1] = (BYTE)((sum_c * div + 16384) >> 15);
798 }
799 }
800
801 static void accumulate_line_yuy2(BYTE* c_plane, const BYTE** planeP, int planes, size_t width, BYTE threshold_luma, BYTE threshold_chroma, int div, IScriptEnvironment* env)
802 {
803 #ifdef INTEL_INTRINSICS
804 if ((env->GetCPUFlags() & CPUF_SSE2) && width >= 16) {
805 accumulate_line_sse2<false>(c_plane, planeP, planes, width, threshold_luma | (threshold_chroma << 8), div);
806 } else
807 #ifdef X86_32
808 if ((env->GetCPUFlags() & CPUF_MMX) && width >= 8) {
809 accumulate_line_mmx(c_plane, planeP, planes, width, threshold_luma | (threshold_chroma << 8), div); //yuy2 is always at least mod8
810 } else
811 #endif
812 #endif
813 accumulate_line_yuy2_c(c_plane, planeP, planes, width, threshold_luma, threshold_chroma, div);
814 }
815
816 35 static void accumulate_line(BYTE* c_plane, const BYTE** planeP, int planes, size_t rowsize, BYTE threshold, int div, int pixelsize, int bits_per_pixel, IScriptEnvironment* env) {
817 // threshold == 255: simple average
818 35 bool maxThreshold = (threshold == 255);
819 #ifdef INTEL_INTRINSICS
820
6/8
✓ Branch 2 → 3 taken 15 times.
✓ Branch 2 → 7 taken 20 times.
✓ Branch 4 → 5 taken 15 times.
✗ Branch 4 → 7 not taken.
✓ Branch 5 → 6 taken 15 times.
✗ Branch 5 → 7 not taken.
✓ Branch 8 → 9 taken 15 times.
✓ Branch 8 → 16 taken 20 times.
35 if ((pixelsize == 2) && (env->GetCPUFlags() & CPUF_SSE4) && rowsize >= 16) {
821 // <maxThreshold, lessThan16bit>
822
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 13 taken 15 times.
15 if(maxThreshold) {
823 if(bits_per_pixel < 16)
824 accumulate_line_16_sse41<true, true>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel);
825 else
826 accumulate_line_16_sse41<true, false>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel);
827 }
828 else {
829
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 15 times.
15 if (bits_per_pixel < 16)
830 accumulate_line_16_sse41<false, true>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel);
831 else
832 15 accumulate_line_16_sse41<false, false>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel);
833 }
834
2/8
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 21 taken 20 times.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 21 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 30 taken 20 times.
20 } else if ((pixelsize == 2) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) {
835 // <maxThreshold, lessThan16bit>
836 if(maxThreshold) {
837 if(bits_per_pixel < 16)
838 accumulate_line_16_sse2<true, true>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel);
839 else
840 accumulate_line_16_sse2<true, false>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel);
841 }
842 else {
843 if (bits_per_pixel < 16)
844 accumulate_line_16_sse2<false, true>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel);
845 else
846 accumulate_line_16_sse2<false, false>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel);
847 }
848 }
849
6/8
✓ Branch 30 → 31 taken 11 times.
✓ Branch 30 → 35 taken 9 times.
✓ Branch 32 → 33 taken 11 times.
✗ Branch 32 → 35 not taken.
✓ Branch 33 → 34 taken 11 times.
✗ Branch 33 → 35 not taken.
✓ Branch 36 → 37 taken 11 times.
✓ Branch 36 → 40 taken 9 times.
20 else if ((pixelsize == 1) && (env->GetCPUFlags() & CPUF_SSSE3) && rowsize >= 16) {
850
1/2
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 11 times.
11 if (maxThreshold) // <maxThreshold
851 accumulate_line_ssse3<true>(c_plane, planeP, planes, rowsize, threshold | (threshold << 8), div);
852 else
853 11 accumulate_line_ssse3<false>(c_plane, planeP, planes, rowsize, threshold | (threshold << 8), div);
854
2/8
✗ Branch 40 → 41 not taken.
✓ Branch 40 → 45 taken 9 times.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 45 not taken.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 45 not taken.
✗ Branch 46 → 47 not taken.
✓ Branch 46 → 50 taken 9 times.
9 } else if ((pixelsize == 1) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) {
855 if (maxThreshold)
856 accumulate_line_sse2<true>(c_plane, planeP, planes, rowsize, threshold | (threshold << 8), div);
857 else
858 accumulate_line_sse2<false>(c_plane, planeP, planes, rowsize, threshold | (threshold << 8), div);
859 }
860 else
861 #ifdef X86_32
862 if ((pixelsize == 1) && (env->GetCPUFlags() & CPUF_MMX) && rowsize >= 8) {
863 size_t mod8_width = rowsize / 8 * 8;
864 accumulate_line_mmx(c_plane, planeP, planes, rowsize, threshold | (threshold << 8), div);
865
866 if (mod8_width != rowsize) {
867 accumulate_line_c<uint8_t, false>(c_plane, planeP, planes, mod8_width, rowsize - mod8_width, threshold, div, bits_per_pixel);
868 }
869 } else
870 #endif
871 #endif
872
873 {
874
1/4
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 55 not taken.
✓ Branch 50 → 59 taken 9 times.
✗ Branch 50 → 63 not taken.
9 switch(pixelsize) {
875 case 1:
876 if (maxThreshold)
877 accumulate_line_c<uint8_t, true>(c_plane, planeP, planes, 0, rowsize, threshold, div, bits_per_pixel);
878 else
879 accumulate_line_c<uint8_t, false>(c_plane, planeP, planes, 0, rowsize, threshold, div, bits_per_pixel);
880 break;
881 case 2:
882 if (maxThreshold)
883 accumulate_line_c<uint16_t, true>(c_plane, planeP, planes, 0, rowsize, threshold, div, bits_per_pixel);
884 else
885 accumulate_line_c<uint16_t, false>(c_plane, planeP, planes, 0, rowsize, threshold, div, bits_per_pixel);
886 break;
887 9 case 4:
888
1/2
✗ Branch 59 → 60 not taken.
✓ Branch 59 → 61 taken 9 times.
9 if (maxThreshold)
889 accumulate_line_c<float, true>(c_plane, planeP, planes, 0, rowsize, threshold, div, bits_per_pixel);
890 else
891 9 accumulate_line_c<float, false>(c_plane, planeP, planes, 0, rowsize, threshold, div, bits_per_pixel);
892 9 break;
893 }
894 }
895 35 }
896
897 template<typename pixel_t>
898 static int64_t calculate_sad_c(const BYTE* cur_ptr, const BYTE* other_ptr, int cur_pitch, int other_pitch, size_t rowsize, size_t height)
899 {
900 const pixel_t *ptr1 = reinterpret_cast<const pixel_t *>(cur_ptr);
901 const pixel_t *ptr2 = reinterpret_cast<const pixel_t *>(other_ptr);
902 size_t width = rowsize / sizeof(pixel_t);
903 cur_pitch /= sizeof(pixel_t);
904 other_pitch /= sizeof(pixel_t);
905
906 // for fullframe float may loose precision
907 typedef typename std::conditional < std::is_floating_point<pixel_t>::value, double, int64_t>::type sum_t;
908 // for one row int is enough and faster than int64
909 typedef typename std::conditional < std::is_floating_point<pixel_t>::value, float, int>::type sumrow_t;
910 sum_t sum = 0;
911
912 for (size_t y = 0; y < height; ++y) {
913 sumrow_t sumrow = 0;
914 for (size_t x = 0; x < width; ++x) {
915 sumrow += std::abs(ptr1[x] - ptr2[x]);
916 }
917 sum += sumrow;
918 ptr1 += cur_pitch;
919 ptr2 += other_pitch;
920 }
921 if (std::is_floating_point<pixel_t>::value)
922 return (int64_t)(sum * 255); // scale 0..1 based sum to 8 bit range
923 else
924 return (int64_t)sum; // for int, scaling to 8 bit range is done outside
925 }
926
927 // sum of byte-diffs.
928 static int64_t calculate_sad(const BYTE* cur_ptr, const BYTE* other_ptr, int cur_pitch, int other_pitch, size_t rowsize, size_t height, int pixelsize, int bits_per_pixel, IScriptEnvironment* env) {
929 #ifdef INTEL_INTRINSICS
930 // todo: sse for float
931 if ((pixelsize == 1) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) {
932 return (int64_t)calculate_sad_sse2<false>(cur_ptr, other_ptr, cur_pitch, other_pitch, rowsize, height);
933 }
934 #ifdef X86_32
935 if ((pixelsize ==1 ) && (env->GetCPUFlags() & CPUF_INTEGER_SSE) && rowsize >= 8) {
936 return (int64_t)calculate_sad_isse(cur_ptr, other_ptr, cur_pitch, other_pitch, rowsize, height);
937 }
938 #endif
939 // sse2 uint16_t
940 if ((pixelsize == 2) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) {
941 return calculate_sad_8_or_16_sse2<uint16_t, false>(cur_ptr, other_ptr, cur_pitch, other_pitch, rowsize, height) >> (bits_per_pixel-8);
942 }
943 #endif
944
945 switch(pixelsize) {
946 case 1: return calculate_sad_c<uint8_t>(cur_ptr, other_ptr, cur_pitch, other_pitch, rowsize, height);
947 case 2: return calculate_sad_c<uint16_t>(cur_ptr, other_ptr, cur_pitch, other_pitch, rowsize, height) >> (bits_per_pixel-8); // scale back to 8 bit range;
948 default: // case 4
949 return calculate_sad_c<float>(cur_ptr, other_ptr, cur_pitch, other_pitch, rowsize, height);
950 }
951 }
952
953 4 PVideoFrame TemporalSoften::GetFrame(int n, IScriptEnvironment* env)
954 {
955 4 int radius = (kernel-1) / 2;
956 4 int c = 0;
957
958 // Just skip if silly settings
959
960
2/6
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 4 times.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 10 taken 4 times.
4 if ((!luma_threshold && !chroma_threshold) || !radius)
961 {
962 PVideoFrame ret = child->GetFrame(n, env); // P.F.
963 return ret;
964 }
965
966 bool planeDisabled[16];
967
968
2/2
✓ Branch 12 → 11 taken 64 times.
✓ Branch 12 → 13 taken 4 times.
68 for (int p = 0; p<16; p++) {
969 64 planeDisabled[p] = false;
970 }
971
972 4 std::vector<PVideoFrame> frames;
973
1/2
✓ Branch 14 → 15 taken 4 times.
✗ Branch 14 → 124 not taken.
4 frames.reserve(kernel);
974
975
2/2
✓ Branch 29 → 16 taken 12 times.
✓ Branch 29 → 30 taken 4 times.
16 for (int p = n - radius; p <= n + radius; ++p) {
976
3/6
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 12 times.
✓ Branch 25 → 26 taken 12 times.
✗ Branch 25 → 120 not taken.
✓ Branch 26 → 27 taken 12 times.
✗ Branch 26 → 118 not taken.
24 frames.emplace_back(child->GetFrame(clamp(p, 0, vi.num_frames - 1), env));
977 }
978
979 // P.F. 16.04.06 leak fix r1841 after 8 days of bug chasing:
980 // Reason #1 of the random QTGMC memory leaks (stuck frame refcounts)
981 // MakeWritable alters the pointer if it is not yet writeable, thus the original PVideoFrame won't be freed (refcount decremented)
982 // To fix this, we leave the frame[] array in its place and copy frame[radius] to CenterFrame and make further write operations on this new frame.
983 // env->MakeWritable(&frames[radius]); // old culprit line. if not yet writeable -> gives another pointer
984
1/2
✓ Branch 31 → 32 taken 4 times.
✗ Branch 31 → 124 not taken.
4 PVideoFrame CenterFrame = frames[radius];
985
1/2
✓ Branch 32 → 33 taken 4 times.
✗ Branch 32 → 122 not taken.
4 env->MakeWritable(&CenterFrame);
986
987 do {
988 const BYTE* planeP[16];
989 const BYTE* planeP2[16];
990 int planePitch[16];
991 int planePitch2[16];
992
993 10 int current_thresh = planes[c].threshold; // Threshold for current plane.
994 10 int d = 0;
995
2/2
✓ Branch 41 → 34 taken 10 times.
✓ Branch 41 → 42 taken 10 times.
20 for (int i = 0; i<radius; i++) { // Fetch all planes sequencially
996
1/2
✓ Branch 36 → 37 taken 10 times.
✗ Branch 36 → 121 not taken.
10 planePitch[d] = frames[i]->GetPitch(planes[c].planeId);
997
1/2
✓ Branch 39 → 40 taken 10 times.
✗ Branch 39 → 121 not taken.
10 planeP[d++] = frames[i]->GetReadPtr(planes[c].planeId);
998 }
999
1000 // BYTE* c_plane = frames[radius]->GetWritePtr(planes[c]);
1001
1/2
✓ Branch 43 → 44 taken 10 times.
✗ Branch 43 → 121 not taken.
10 BYTE* c_plane = CenterFrame->GetWritePtr(planes[c].planeId); // P.F. using CenterFrame for write access
1002
1003
2/2
✓ Branch 52 → 45 taken 10 times.
✓ Branch 52 → 53 taken 10 times.
20 for (int i = 1; i<=radius; i++) { // Fetch all planes sequencially
1004
1/2
✓ Branch 47 → 48 taken 10 times.
✗ Branch 47 → 121 not taken.
10 planePitch[d] = frames[radius+i]->GetPitch(planes[c].planeId);
1005
1/2
✓ Branch 50 → 51 taken 10 times.
✗ Branch 50 → 121 not taken.
10 planeP[d++] = frames[radius+i]->GetReadPtr(planes[c].planeId);
1006 }
1007
1008
1/2
✓ Branch 54 → 55 taken 10 times.
✗ Branch 54 → 121 not taken.
10 int rowsize = CenterFrame->GetRowSize(planes[c].planeId|PLANAR_ALIGNED);
1009
1/2
✓ Branch 56 → 57 taken 10 times.
✗ Branch 56 → 121 not taken.
10 int h = CenterFrame->GetHeight(planes[c].planeId);
1010
1/2
✓ Branch 58 → 59 taken 10 times.
✗ Branch 58 → 121 not taken.
10 int pitch = CenterFrame->GetPitch(planes[c].planeId);
1011
1012
1/2
✗ Branch 59 → 60 not taken.
✓ Branch 59 → 90 taken 10 times.
10 if (scenechange>0) {
1013 int d2 = 0;
1014 bool skiprest = false;
1015 for (int i = radius-1; i>=0; i--) { // Check frames backwards
1016 if ((!skiprest) && (!planeDisabled[i])) {
1017 int sad = (int)calculate_sad(c_plane, planeP[i], pitch, planePitch[i], CenterFrame->GetRowSize(planes[c].planeId), h, pixelsize, bits_per_pixel, env);
1018 if (sad < scenechange) {
1019 planePitch2[d2] = planePitch[i];
1020 planeP2[d2++] = planeP[i];
1021 } else {
1022 skiprest = true;
1023 }
1024 planeDisabled[i] = skiprest; // Disable this frame on next plane (so that Y can affect UV)
1025 } else {
1026 planeDisabled[i] = true;
1027 }
1028 }
1029 skiprest = false;
1030 for (int i = radius; i < 2*radius; i++) { // Check forward frames
1031 if ((!skiprest) && (!planeDisabled[i])) { // Disable this frame on next plane (so that Y can affect UV)
1032 int sad = (int)calculate_sad(c_plane, planeP[i], pitch, planePitch[i], CenterFrame->GetRowSize(planes[c].planeId), h, pixelsize, bits_per_pixel, env);
1033 if (sad < scenechange) {
1034 planePitch2[d2] = planePitch[i];
1035 planeP2[d2++] = planeP[i];
1036 } else {
1037 skiprest = true;
1038 }
1039 planeDisabled[i] = skiprest;
1040 } else {
1041 planeDisabled[i] = true;
1042 }
1043 }
1044
1045 //Copy back
1046 for (int i = 0; i<d2; i++) {
1047 planeP[i] = planeP2[i];
1048 planePitch[i] = planePitch2[i];
1049 }
1050 d = d2;
1051 }
1052
1053
1/2
✗ Branch 90 → 91 not taken.
✓ Branch 90 → 98 taken 10 times.
10 if (d < 1)
1054 {
1055 // Memory leak reason #2 r1841: this wasn't here before return
1056 for (int i = 0; i < kernel; ++i)
1057 frames[i] = nullptr;
1058 // return frames[radius];
1059 return CenterFrame; // return the modified frame
1060 }
1061
1062 10 int c_div = 32768/(d+1); // We also have the tetplane included, thus d+1.
1063
1/2
✓ Branch 98 → 99 taken 10 times.
✗ Branch 98 → 109 not taken.
10 if (current_thresh) {
1064 // for threshold==255 -> simple average
1065
2/2
✓ Branch 108 → 100 taken 35 times.
✓ Branch 108 → 109 taken 10 times.
45 for (int y = 0; y<h; y++) { // One line at the time
1066
2/4
✓ Branch 100 → 101 taken 35 times.
✗ Branch 100 → 121 not taken.
✗ Branch 101 → 102 not taken.
✓ Branch 101 → 103 taken 35 times.
35 if (vi.IsYUY2()) {
1067 accumulate_line_yuy2(c_plane, planeP, d, rowsize, luma_threshold, chroma_threshold, c_div, env);
1068 } else {
1069
1/2
✓ Branch 103 → 104 taken 35 times.
✗ Branch 103 → 121 not taken.
35 accumulate_line(c_plane, planeP, d, rowsize, current_thresh, c_div, pixelsize, bits_per_pixel, env);
1070 }
1071
2/2
✓ Branch 106 → 105 taken 70 times.
✓ Branch 106 → 107 taken 35 times.
105 for (int p = 0; p<d; p++)
1072 70 planeP[p] += planePitch[p];
1073 35 c_plane += pitch;
1074 }
1075 } else { // Just maintain the plane
1076 }
1077 10 c++;
1078
2/2
✓ Branch 111 → 33 taken 6 times.
✓ Branch 111 → 112 taken 4 times.
10 } while (planes[c].planeId);
1079
1080 // PVideoFrame result = frames[radius]; // we are using CenterFrame instead
1081 // return result;
1082
1/2
✓ Branch 112 → 113 taken 4 times.
✗ Branch 112 → 122 not taken.
4 return CenterFrame;
1083 4 }
1084
1085
1086 AVSValue __cdecl TemporalSoften::Create(AVSValue args, void*, IScriptEnvironment* env)
1087 {
1088 return new TemporalSoften( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(),
1089 args[3].AsInt(), args[4].AsInt(0),/*args[5].AsInt(1),*/env ); //ignore mode parameter
1090 }
1091
1092
1093
1094 /****************************
1095 **** Spatial Soften *****
1096 ***************************/
1097
1098 2 SpatialSoften::SpatialSoften( PClip _child, int _radius, unsigned _luma_threshold,
1099 2 unsigned _chroma_threshold, IScriptEnvironment* env )
1100 : GenericVideoFilter(_child),
1101 2 luma_threshold(_luma_threshold), chroma_threshold(_chroma_threshold),
1102
2/4
✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 9 not taken.
2 diameter(_radius * 2 + 1)
1103 {
1104
2/4
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 12 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 2 times.
2 if (!vi.IsYUY2())
1105 env->ThrowError("SpatialSoften: requires YUY2 input");
1106 2 }
1107
1108
1109 1 PVideoFrame SpatialSoften::GetFrame(int n, IScriptEnvironment* env)
1110 {
1111
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 66 not taken.
1 PVideoFrame src = child->GetFrame(n, env);
1112
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 64 not taken.
1 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
1113
1114
1/2
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 62 not taken.
1 const BYTE* srcp = src->GetReadPtr();
1115
1/2
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 62 not taken.
1 BYTE* dstp = dst->GetWritePtr();
1116
1/2
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 62 not taken.
1 int src_pitch = src->GetPitch();
1117
1/2
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 62 not taken.
1 int dst_pitch = dst->GetPitch();
1118
1/2
✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 62 not taken.
1 int row_size = src->GetRowSize();
1119
1120
2/2
✓ Branch 58 → 16 taken 3 times.
✓ Branch 58 → 59 taken 1 time.
4 for (int y=0; y<vi.height; ++y)
1121 {
1122 const BYTE* line[65]; // better not make diameter bigger than this...
1123
2/2
✓ Branch 26 → 17 taken 9 times.
✓ Branch 26 → 27 taken 3 times.
12 for (int h=0; h<diameter; ++h)
1124
2/2
✓ Branch 17 → 18 taken 1 time.
✓ Branch 17 → 19 taken 8 times.
18 line[h] = &srcp[src_pitch * clamp(y+h-(diameter>>1), 0, vi.height-1)];
1125 int x;
1126
1127 3 int edge = (diameter+1) & -4;
1128
2/2
✓ Branch 29 → 28 taken 12 times.
✓ Branch 29 → 30 taken 3 times.
15 for (x=0; x<edge; ++x) // diameter-1 == (diameter>>1) * 2
1129 12 dstp[y*dst_pitch + x] = srcp[y*src_pitch + x];
1130
2/2
✓ Branch 53 → 31 taken 12 times.
✓ Branch 53 → 54 taken 3 times.
15 for (; x < row_size - edge; x+=2)
1131 {
1132 12 int cnt=0, _y=0, _u=0, _v=0;
1133 12 int xx = x | 3;
1134 12 int Y = srcp[y*src_pitch + x], U = srcp[y*src_pitch + xx - 2], V = srcp[y*src_pitch + xx];
1135
2/2
✓ Branch 49 → 32 taken 36 times.
✓ Branch 49 → 50 taken 12 times.
48 for (int h=0; h<diameter; ++h)
1136 {
1137
2/2
✓ Branch 47 → 33 taken 108 times.
✓ Branch 47 → 48 taken 36 times.
144 for (int w = -diameter+1; w < diameter; w += 2)
1138 {
1139 108 int xw = (x+w) | 3;
1140
1/2
✓ Branch 38 → 39 taken 36 times.
✗ Branch 38 → 43 not taken.
144 if (IsClose(line[h][x+w], Y, luma_threshold) && IsClose(line[h][xw-2], U,
1141
6/6
✓ Branch 35 → 36 taken 36 times.
✓ Branch 35 → 43 taken 72 times.
✓ Branch 41 → 42 taken 20 times.
✓ Branch 41 → 43 taken 16 times.
✓ Branch 44 → 45 taken 20 times.
✓ Branch 44 → 46 taken 88 times.
180 chroma_threshold) && IsClose(line[h][xw], V, chroma_threshold))
1142 {
1143 20 ++cnt; _y += line[h][x+w]; _u += line[h][xw-2]; _v += line[h][xw];
1144 }
1145 }
1146 }
1147 12 dstp[y*dst_pitch + x] = (_y + (cnt>>1)) / cnt;
1148
2/2
✓ Branch 50 → 51 taken 6 times.
✓ Branch 50 → 52 taken 6 times.
12 if (!(x&3)) {
1149 6 dstp[y*dst_pitch + x+1] = (_u + (cnt>>1)) / cnt;
1150 6 dstp[y*dst_pitch + x+3] = (_v + (cnt>>1)) / cnt;
1151 }
1152 }
1153
2/2
✓ Branch 56 → 55 taken 12 times.
✓ Branch 56 → 57 taken 3 times.
15 for (; x<row_size; ++x)
1154 12 dstp[y*dst_pitch + x] = srcp[y*src_pitch + x];
1155 }
1156
1157 1 return dst;
1158 1 }
1159
1160
1161 AVSValue __cdecl SpatialSoften::Create(AVSValue args, void*, IScriptEnvironment* env)
1162 {
1163 return new SpatialSoften( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(),
1164 args[3].AsInt(), env );
1165 }
1166