GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 48.2% 877 / 0 / 1819
Functions: 55.2% 32 / 0 / 58
Branches: 34.3% 661 / 0 / 1929

filters/levels.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
36 #include "levels.h"
37 #include <float.h>
38 #include "limiter.h"
39 #include <cstdio>
40 #include <cmath>
41 #include <avs/minmax.h>
42 #include <avs/alignment.h>
43 #include "../core/internal.h"
44 #include <algorithm>
45 #include <string>
46
47 #define PI 3.141592653589793
48
49
50 /********************************************************************
51 ***** Declare index of new filters for Avisynth's filter engine *****
52 ********************************************************************/
53
54 extern const AVSFunction Levels_filters[] = {
55 { "Levels", BUILTIN_FUNC_PREFIX, "cfffff[coring]b[dither]b", Levels::Create }, // src_low, gamma, src_high, dst_low, dst_high cifiii->ffffff
56 { "RGBAdjust", BUILTIN_FUNC_PREFIX, "c[r]f[g]f[b]f[a]f[rb]f[gb]f[bb]f[ab]f[rg]f[gg]f[bg]f[ag]f[analyze]b[dither]b[conditional]b[condvarsuffix]s", RGBAdjust::Create },
57 // 'sse': unused even on INTEL, just for script compatibility
58 { "Tweak", BUILTIN_FUNC_PREFIX, "c[hue]f[sat]f[bright]f[cont]f[coring]b[sse]b[startHue]f[endHue]f[maxSat]f[minSat]f[interp]f[dither]b[realcalc]b[dither_strength]f", Tweak::Create },
59 { "MaskHS", BUILTIN_FUNC_PREFIX, "c[startHue]f[endHue]f[maxSat]f[minSat]f[coring]b[realcalc]b", MaskHS::Create },
60 { "Limiter", BUILTIN_FUNC_PREFIX, "c[min_luma]f[max_luma]f[min_chroma]f[max_chroma]f[show]s[paramscale]b", Limiter::Create },
61 { 0 }
62 };
63
64
65 avs_alignas(64) static const BYTE ditherMap[256] = {
66 #if 0
67 // default 0231 recursed table
68 0x00, 0x80, 0x20, 0xA0, 0x08, 0x88, 0x28, 0xA8, 0x02, 0x82, 0x22, 0xA2, 0x0A, 0x8A, 0x2A, 0xAA,
69 0xC0, 0x40, 0xE0, 0x60, 0xC8, 0x48, 0xE8, 0x68, 0xC2, 0x42, 0xE2, 0x62, 0xCA, 0x4A, 0xEA, 0x6A,
70 0x30, 0xB0, 0x10, 0x90, 0x38, 0xB8, 0x18, 0x98, 0x32, 0xB2, 0x12, 0x92, 0x3A, 0xBA, 0x1A, 0x9A,
71 0xF0, 0x70, 0xD0, 0x50, 0xF8, 0x78, 0xD8, 0x58, 0xF2, 0x72, 0xD2, 0x52, 0xFA, 0x7A, 0xDA, 0x5A,
72
73 0x0C, 0x8C, 0x2C, 0xAC, 0x04, 0x84, 0x24, 0xA4, 0x0E, 0x8E, 0x2E, 0xAE, 0x06, 0x86, 0x26, 0xA6,
74 0xCC, 0x4C, 0xEC, 0x6C, 0xC4, 0x44, 0xE4, 0x64, 0xCE, 0x4E, 0xEE, 0x6E, 0xC6, 0x46, 0xE6, 0x66,
75 0x3C, 0xBC, 0x1C, 0x9C, 0x34, 0xB4, 0x14, 0x94, 0x3E, 0xBE, 0x1E, 0x9E, 0x36, 0xB6, 0x16, 0x96,
76 0xFC, 0x7C, 0xDC, 0x5C, 0xF4, 0x74, 0xD4, 0x54, 0xFE, 0x7E, 0xDE, 0x5E, 0xF6, 0x76, 0xD6, 0x56,
77
78 0x03, 0x83, 0x23, 0xA3, 0x0B, 0x8B, 0x2B, 0xAB, 0x01, 0x81, 0x21, 0xA1, 0x09, 0x89, 0x29, 0xA9,
79 0xC3, 0x43, 0xE3, 0x63, 0xCB, 0x4B, 0xEB, 0x6B, 0xC1, 0x41, 0xE1, 0x61, 0xC9, 0x49, 0xE9, 0x69,
80 0x33, 0xB3, 0x13, 0x93, 0x3B, 0xBB, 0x1B, 0x9B, 0x31, 0xB1, 0x11, 0x91, 0x39, 0xB9, 0x19, 0x99,
81 0xF3, 0x73, 0xD3, 0x53, 0xFB, 0x7B, 0xDB, 0x5B, 0xF1, 0x71, 0xD1, 0x51, 0xF9, 0x79, 0xD9, 0x59,
82
83 0x0F, 0x8F, 0x2F, 0xAF, 0x07, 0x87, 0x27, 0xA7, 0x0D, 0x8D, 0x2D, 0xAD, 0x05, 0x85, 0x25, 0xA5,
84 0xCF, 0x4F, 0xEF, 0x6F, 0xC7, 0x47, 0xE7, 0x67, 0xCD, 0x4D, 0xED, 0x6D, 0xC5, 0x45, 0xE5, 0x65,
85 0x3F, 0xBF, 0x1F, 0x9F, 0x37, 0xB7, 0x17, 0x97, 0x3D, 0xBD, 0x1D, 0x9D, 0x35, 0xB5, 0x15, 0x95,
86 0xFF, 0x7F, 0xDF, 0x5F, 0xF7, 0x77, 0xD7, 0x57, 0xFD, 0x7D, 0xDD, 0x5D, 0xF5, 0x75, 0xD5, 0x55,
87 #else
88 // improved "equal sum" modified table
89 0x00, 0xB0, 0x60, 0xD0, 0x0B, 0xBB, 0x6B, 0xDB, 0x06, 0xB6, 0x66, 0xD6, 0x0D, 0xBD, 0x6D, 0xDD,
90 0xC0, 0x70, 0x90, 0x20, 0xCB, 0x7B, 0x9B, 0x2B, 0xC6, 0x76, 0x96, 0x26, 0xCD, 0x7D, 0x9D, 0x2D,
91 0x30, 0x80, 0x50, 0xE0, 0x3B, 0x8B, 0x5B, 0xEB, 0x36, 0x86, 0x56, 0xE6, 0x3D, 0x8D, 0x5D, 0xED,
92 0xF0, 0x40, 0xA0, 0x10, 0xFB, 0x4B, 0xAB, 0x1B, 0xF6, 0x46, 0xA6, 0x16, 0xFD, 0x4D, 0xAD, 0x1D,
93
94 0x0C, 0xBC, 0x6C, 0xDC, 0x07, 0xB7, 0x67, 0xD7, 0x09, 0xB9, 0x69, 0xD9, 0x02, 0xB2, 0x62, 0xD2,
95 0xCC, 0x7C, 0x9C, 0x2C, 0xC7, 0x77, 0x97, 0x27, 0xC9, 0x79, 0x99, 0x29, 0xC2, 0x72, 0x92, 0x22,
96 0x3C, 0x8C, 0x5C, 0xEC, 0x37, 0x87, 0x57, 0xE7, 0x39, 0x89, 0x59, 0xE9, 0x32, 0x82, 0x52, 0xE2,
97 0xFC, 0x4C, 0xAC, 0x1C, 0xF7, 0x47, 0xA7, 0x17, 0xF9, 0x49, 0xA9, 0x19, 0xF2, 0x42, 0xA2, 0x12,
98
99 0x03, 0xB3, 0x63, 0xD3, 0x08, 0xB8, 0x68, 0xD8, 0x05, 0xB5, 0x65, 0xD5, 0x0E, 0xBE, 0x6E, 0xDE,
100 0xC3, 0x73, 0x93, 0x23, 0xC8, 0x78, 0x98, 0x28, 0xC5, 0x75, 0x95, 0x25, 0xCE, 0x7E, 0x9E, 0x2E,
101 0x33, 0x83, 0x53, 0xE3, 0x38, 0x88, 0x58, 0xE8, 0x35, 0x85, 0x55, 0xE5, 0x3E, 0x8E, 0x5E, 0xEE,
102 0xF3, 0x43, 0xA3, 0x13, 0xF8, 0x48, 0xA8, 0x18, 0xF5, 0x45, 0xA5, 0x15, 0xFE, 0x4E, 0xAE, 0x1E,
103
104 0x0F, 0xBF, 0x6F, 0xDF, 0x04, 0xB4, 0x64, 0xD4, 0x0A, 0xBA, 0x6A, 0xDA, 0x01, 0xB1, 0x61, 0xD1,
105 0xCF, 0x7F, 0x9F, 0x2F, 0xC4, 0x74, 0x94, 0x24, 0xCA, 0x7A, 0x9A, 0x2A, 0xC1, 0x71, 0x91, 0x21,
106 0x3F, 0x8F, 0x5F, 0xEF, 0x34, 0x84, 0x54, 0xE4, 0x3A, 0x8A, 0x5A, 0xEA, 0x31, 0x81, 0x51, 0xE1,
107 0xFF, 0x4F, 0xAF, 0x1F, 0xF4, 0x44, 0xA4, 0x14, 0xFA, 0x4A, 0xAA, 0x1A, 0xF1, 0x41, 0xA1, 0x11,
108 #endif
109 };
110
111
112 avs_alignas(16) static const BYTE ditherMap4[16] = {
113 0x0, 0xB, 0x6, 0xD,
114 0xC, 0x7, 0x9, 0x2,
115 0x3, 0x8, 0x5, 0xE,
116 0xF, 0x4, 0xA, 0x1,
117 };
118
119 8 static void __cdecl free_buffer(void* buff, IScriptEnvironment* env)
120 {
121
1/2
✓ Branch 2 → 3 taken 8 times.
✗ Branch 2 → 4 not taken.
8 if (buff) {
122 8 static_cast<IScriptEnvironment2*>(env)->Free(buff);
123 }
124 8 }
125
126 // Helper for Limits, MaskHS, Tweak
127 15 static void get_limits(luma_chroma_limits_t &d, int bits_per_pixel) {
128 15 int tv_range_lo_luma_8 = 16;
129 15 int tv_range_hi_luma_8 = 235;
130 15 int tv_range_lo_chroma_8 = tv_range_lo_luma_8;
131 15 int tv_range_hi_chroma_8 = 240;
132
133
2/2
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 4 taken 13 times.
15 if (bits_per_pixel == 32) {
134 2 d.tv_range_low_luma_f = tv_range_lo_luma_8 / 255.0f;
135 2 d.tv_range_hi_luma_f = tv_range_hi_luma_8 / 255.0f;
136 2 d.full_range_low_luma_f = 0.0f;
137 2 d.full_range_hi_luma_f = 1.0f;
138 #ifdef FLOAT_CHROMA_IS_HALF_CENTERED
139 d.middle_chroma_f = 0.5f;
140 #else
141 2 d.middle_chroma_f = 0.0f;
142 #endif
143 2 d.tv_range_low_chroma_f = (tv_range_lo_chroma_8 - 128) / 255.0f + d.middle_chroma_f; // -112
144 2 d.tv_range_hi_chroma_f = (tv_range_hi_chroma_8 - 128) / 255.0f + d.middle_chroma_f; // 112
145 2 d.full_range_low_chroma_f = d.middle_chroma_f - 0.5f; // -0.5..0.5 or 0..1.0
146 2 d.full_range_hi_chroma_f = d.middle_chroma_f + 0.5f;
147
148 2 d.range_luma_f = d.tv_range_hi_luma_f - d.tv_range_low_luma_f;
149 2 d.range_chroma_f = d.tv_range_hi_chroma_f - d.tv_range_low_chroma_f;
150 }
151 else {
152 13 d.tv_range_low = tv_range_lo_luma_8 << (bits_per_pixel - 8); // 16-240,64-960, 256-3852,... 4096-61692
153 13 d.tv_range_hi_luma = tv_range_hi_luma_8 << (bits_per_pixel - 8);
154 13 d.tv_range_hi_chroma = tv_range_hi_chroma_8 << (bits_per_pixel - 8);
155 13 d.middle_chroma = 1 << (bits_per_pixel - 1); // 128
156 13 d.range_luma = d.tv_range_hi_luma - d.tv_range_low; // 219
157 13 d.range_chroma = d.tv_range_hi_chroma - d.tv_range_low; // 224
158 }
159 15 }
160
161 /********************************
162 ******* Levels Filter ******
163 ********************************/
164
165 template<bool chroma, bool use_gamma>
166 AVS_FORCEINLINE float Levels::calcPixel(const float pixel)
167 {
168 float result;
169 if (!chroma) {
170 float p;
171
1/16
✗ Branch 237 → 238 not taken.
✗ Branch 237 → 239 not taken.
✗ Branch 253 → 254 not taken.
✗ Branch 253 → 255 not taken.
✗ Branch 312 → 313 not taken.
✗ Branch 312 → 314 not taken.
✗ Branch 346 → 347 not taken.
✗ Branch 346 → 348 not taken.
✗ Branch 385 → 386 not taken.
✓ Branch 385 → 387 taken 10 times.
✗ Branch 401 → 402 not taken.
✗ Branch 401 → 403 not taken.
✗ Branch 460 → 461 not taken.
✗ Branch 460 → 462 not taken.
✗ Branch 494 → 495 not taken.
✗ Branch 494 → 496 not taken.
10 if (coring)
172 p = ((pixel - limits.tv_range_low_luma_f)*(1.0f / limits.range_luma_f) - in_min_f) / divisor_f;
173 else
174 10 p = (pixel - in_min_f) / divisor_f;
175
176 if(use_gamma)
177 10 p = (float)pow((double)clamp(p, 0.0f, 1.0f), gamma);
178
179 10 p = p * out_diff_f + out_min_f; // out_diff_f = out_max_f - out_min_f;
180 // luma
181
1/32
✗ Branch 241 → 242 not taken.
✗ Branch 241 → 243 not taken.
✗ Branch 256 → 257 not taken.
✗ Branch 256 → 258 not taken.
✗ Branch 316 → 317 not taken.
✗ Branch 316 → 318 not taken.
✗ Branch 325 → 326 not taken.
✗ Branch 325 → 327 not taken.
✗ Branch 334 → 335 not taken.
✗ Branch 334 → 336 not taken.
✗ Branch 349 → 350 not taken.
✗ Branch 349 → 351 not taken.
✗ Branch 357 → 358 not taken.
✗ Branch 357 → 359 not taken.
✗ Branch 365 → 366 not taken.
✗ Branch 365 → 367 not taken.
✗ Branch 389 → 390 not taken.
✓ Branch 389 → 391 taken 10 times.
✗ Branch 404 → 405 not taken.
✗ Branch 404 → 406 not taken.
✗ Branch 464 → 465 not taken.
✗ Branch 464 → 466 not taken.
✗ Branch 473 → 474 not taken.
✗ Branch 473 → 475 not taken.
✗ Branch 482 → 483 not taken.
✗ Branch 482 → 484 not taken.
✗ Branch 497 → 498 not taken.
✗ Branch 497 → 499 not taken.
✗ Branch 505 → 506 not taken.
✗ Branch 505 → 507 not taken.
✗ Branch 513 → 514 not taken.
✗ Branch 513 → 515 not taken.
10 if (coring) {
182 result = clamp(p* limits.range_luma_f / 1.0f + limits.tv_range_low_luma_f, limits.tv_range_low_luma_f, limits.tv_range_hi_luma_f);
183 }
184 else
185 10 result = clamp(p, 0.0f, 1.0f); // todo: theoretical question, should we clamp in Levels function?
186 }
187 else {
188 /*
189 int q = (int)(((bias_dither + ii - middle_chroma * scale) * (out_max - out_min)) / divisor + middle_chroma + 0.5);
190 int chroma;
191 if (coring)
192 chroma = clamp(q, tv_range_low, tv_range_hi_chroma); // e.g. clamp(q, 16, 240)
193 else
194 chroma = clamp(q, 0, max_pixel_value); // e.g. clamp(q, 0, 255)
195 */
196 20 float q = ((pixel - limits.middle_chroma_f) * out_diff_f) / divisor_f + limits.middle_chroma_f;
197
1/4
✗ Branch 279 → 280 not taken.
✗ Branch 279 → 281 not taken.
✗ Branch 427 → 428 not taken.
✓ Branch 427 → 429 taken 10 times.
10 if (coring)
198 result = clamp(q, limits.tv_range_low_chroma_f, limits.tv_range_hi_chroma_f); // e.g. clamp(q, 16, 240)
199 else
200 20 result = clamp(q, limits.full_range_low_chroma_f, limits.full_range_hi_chroma_f); // e.g. clamp(q, 0, 255) todo: theoretical question, should we clamp in Levels function?
201 }
202 30 return result;
203 }
204
205
206 4 Levels::Levels(PClip _child, float _in_min, double _gamma, float _in_max, float _out_min, float _out_max, bool _coring, bool _dither,
207 4 IScriptEnvironment* env)
208
2/4
✓ Branch 2 → 3 taken 4 times.
✗ Branch 2 → 90 not taken.
✓ Branch 3 → 4 taken 4 times.
✗ Branch 3 → 88 not taken.
4 : GenericVideoFilter(_child), coring(_coring), dither(_dither), gamma(_gamma), in_min_f(_in_min), in_max_f(_in_max), out_min_f(_out_min), out_max_f(_out_max)
209 {
210
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 4 times.
4 if (gamma <= 0.0)
211 env->ThrowError("Levels: gamma must be positive");
212
213 4 gamma = 1/gamma;
214 4 use_gamma = (gamma != 1.0);
215
216 4 int in_min = (int)in_min_f;
217 4 int in_max = (int)in_max_f;
218 4 int out_min = (int)out_min_f;
219 4 int out_max = (int)out_max_f;
220 4 out_diff_f = out_max_f - out_min_f;
221
222 int divisor;
223
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 4 times.
4 if (in_min == in_max)
224 divisor = 1;
225 else
226 4 divisor = in_max - in_min;
227
228
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 4 times.
4 if (in_min_f == in_max_f)
229 divisor_f = 1;
230 else
231 4 divisor_f = in_max_f - in_min_f;
232
233 4 int scale = 1;
234 //double bias = 0.0;
235
236 4 dither_strength = 1.0f; // later: from parameter as Tweak
237
238
1/2
✓ Branch 13 → 14 taken 4 times.
✗ Branch 13 → 91 not taken.
4 pixelsize = vi.ComponentSize();
239
1/2
✓ Branch 14 → 15 taken 4 times.
✗ Branch 14 → 91 not taken.
4 bits_per_pixel = vi.BitsPerComponent(); // 8,10..16
240
241 // No lookup for float. Only slow pixel-by-pixel realtime calculation
242
243 4 int lookup_size = 1 << bits_per_pixel; // 256, 1024, 4096, 16384, 65536
244
2/2
✓ Branch 15 → 16 taken 2 times.
✓ Branch 15 → 17 taken 2 times.
4 real_lookup_size = (pixelsize == 1) ? 256 : 65536; // avoids lut overflow in case of non-standard content of a 10 bit clip
245 4 int max_pixel_value = (1 << bits_per_pixel) - 1;
246
247 4 use_lut = bits_per_pixel != 32; // for float: realtime only
248
249 4 get_limits(limits, bits_per_pixel); // tv range limits
250
251
2/2
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 21 taken 3 times.
4 if (pixelsize == 4)
252 1 dither_strength /= 65536.0f; // same dither range as for a 16 bit clip
253
254
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 4 times.
4 if (dither) {
255 // lut scale settings
256 // same 256*dither for chroma and luma
257 scale = 256; // lower 256 is dither value
258 divisor *= 256;
259 in_min *= 256;
260 bias_dither = -(256.0f * dither_strength - 1) / 2; // -127.5 for 8 bit, scaling because of dithershift
261 }
262 else {
263 4 scale = 1;
264 4 bias_dither = 0.0f;
265 }
266
267
5/12
✓ Branch 24 → 25 taken 4 times.
✗ Branch 24 → 91 not taken.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 28 taken 4 times.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 91 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 31 not taken.
✓ Branch 28 → 29 taken 4 times.
✗ Branch 28 → 91 not taken.
✓ Branch 29 → 30 taken 3 times.
✓ Branch 29 → 31 taken 1 time.
4 need_chroma = (vi.IsYUV() || vi.IsYUVA()) && !vi.IsY8();
268
2/4
✓ Branch 32 → 33 taken 4 times.
✗ Branch 32 → 91 not taken.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 4 times.
4 if (vi.IsRGB())
269 coring = false; // no coring option for packed and planar RGBs
270
271 // one buffer for map and mapchroma
272 4 map = nullptr;
273
2/2
✓ Branch 35 → 36 taken 3 times.
✓ Branch 35 → 80 taken 1 time.
4 if (use_lut) {
274
2/2
✓ Branch 36 → 37 taken 2 times.
✓ Branch 36 → 38 taken 1 time.
3 int number_of_maps = need_chroma ? 2 : 1;
275 3 int bufsize = pixelsize * real_lookup_size * scale * number_of_maps;
276
1/2
✓ Branch 39 → 40 taken 3 times.
✗ Branch 39 → 91 not taken.
3 map = static_cast<uint8_t*>(env->Allocate(bufsize, 16, AVS_NORMAL_ALLOC));
277
1/2
✗ Branch 40 → 41 not taken.
✓ Branch 40 → 42 taken 3 times.
3 if (!map)
278 env->ThrowError("Levels: Could not reserve memory.");
279
1/2
✓ Branch 42 → 43 taken 3 times.
✗ Branch 42 → 91 not taken.
3 env->AtExit(free_buffer, map);
280
3/4
✓ Branch 43 → 44 taken 1 time.
✓ Branch 43 → 55 taken 2 times.
✗ Branch 44 → 45 not taken.
✓ Branch 44 → 55 taken 1 time.
3 if (bits_per_pixel > 8 && bits_per_pixel < 16) // make lut table safe for 10-14 bit garbage
281 std::fill_n(map, bufsize, 0); // 8 and 16 bit is safe
282
283
2/2
✓ Branch 55 → 56 taken 2 times.
✓ Branch 55 → 57 taken 1 time.
3 if(need_chroma)
284 2 mapchroma = map + pixelsize * real_lookup_size * scale; // pointer offset
285
286
2/2
✓ Branch 79 → 58 taken 66048 times.
✓ Branch 79 → 87 taken 3 times.
66051 for (int i = 0; i < lookup_size*scale; ++i) {
287 double p;
288
289 int ii;
290
1/2
✗ Branch 58 → 59 not taken.
✓ Branch 58 → 60 taken 66048 times.
66048 if (dither)
291 ii = (i & 0xFFFFFF00) + (int)((i & 0xFF)*dither_strength);
292 else
293 66048 ii = i;
294
295
2/2
✓ Branch 61 → 62 taken 256 times.
✓ Branch 61 → 63 taken 65792 times.
66048 if (coring)
296 256 p = ((bias_dither + ii - limits.tv_range_low *scale)*((double)max_pixel_value / limits.range_luma) - in_min) / divisor;
297 else
298 65792 p = (bias_dither + ii - in_min) / divisor;
299
300 66048 p = pow(clamp(p, 0.0, 1.0), gamma);
301 66048 p = p * (out_max - out_min) + out_min;
302 int luma;
303
2/2
✓ Branch 65 → 66 taken 256 times.
✓ Branch 65 → 67 taken 65792 times.
66048 if (coring)
304 256 luma = clamp(int(p*((double)limits.range_luma / max_pixel_value) + limits.tv_range_low + 0.5), limits.tv_range_low, limits.tv_range_hi_luma);
305 else
306 65792 luma = clamp(int(p + 0.5), 0, max_pixel_value);
307
308
2/2
✓ Branch 68 → 69 taken 512 times.
✓ Branch 68 → 70 taken 65536 times.
66048 if (pixelsize == 1)
309 512 map[i] = (BYTE)luma;
310 else // pixelsize==2
311 65536 reinterpret_cast<uint16_t *>(map)[i] = (uint16_t)luma;
312
313
2/2
✓ Branch 71 → 72 taken 65792 times.
✓ Branch 71 → 78 taken 256 times.
66048 if (need_chroma) {
314 65792 int q = (int)(((bias_dither + ii - limits.middle_chroma*scale) * (out_max - out_min)) / divisor + limits.middle_chroma + 0.5f);
315 int chroma;
316
2/2
✓ Branch 72 → 73 taken 256 times.
✓ Branch 72 → 74 taken 65536 times.
65792 if (coring)
317 256 chroma = clamp(q, limits.tv_range_low, limits.tv_range_hi_chroma); // e.g. clamp(q, 16, 240)
318 else
319 65536 chroma = clamp(q, 0, max_pixel_value); // e.g. clamp(q, 0, 255)
320
2/2
✓ Branch 75 → 76 taken 256 times.
✓ Branch 75 → 77 taken 65536 times.
65792 if (pixelsize == 1)
321 256 mapchroma[i] = (BYTE)chroma;
322 else // pixelsize==2
323 65536 reinterpret_cast<uint16_t *>(mapchroma)[i] = (uint16_t)chroma;
324 }
325 }
326 }
327 else {
328 // precalc float dither table from integer one
329
1/2
✗ Branch 80 → 81 not taken.
✓ Branch 80 → 87 taken 1 time.
1 if (dither) {
330 for (int y = 0; y <= 15; y++)
331 for (int x = 0; x <= 15; x++) {
332 int index = (y << 4) | x; // 0..255
333 ditherMap_f[index] = (ditherMap[index] / 255.0f - 0.5f) * dither_strength;
334 // float dithering is 16 bit granularity, dither_strength is 1/65536.0 and not a parameter yet
335 }
336 }
337 }
338 4 }
339
340
341 4 PVideoFrame __stdcall Levels::GetFrame(int n, IScriptEnvironment* env)
342 {
343 4 PVideoFrame frame = child->GetFrame(n, env);
344
1/2
✓ Branch 4 → 5 taken 4 times.
✗ Branch 4 → 524 not taken.
4 env->MakeWritable(&frame);
345
1/2
✓ Branch 6 → 7 taken 4 times.
✗ Branch 6 → 524 not taken.
4 BYTE* p = frame->GetWritePtr();
346
1/2
✓ Branch 8 → 9 taken 4 times.
✗ Branch 8 → 524 not taken.
4 const int pitch = frame->GetPitch();
347
348
2/2
✓ Branch 9 → 10 taken 3 times.
✓ Branch 9 → 225 taken 1 time.
4 if (use_lut) {
349
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 120 taken 3 times.
3 if (dither) {
350 if (vi.IsYUY2()) {
351 const int UVwidth = vi.width / 2;
352 for (int y = 0; y < vi.height; ++y) {
353 const int _y = (y << 4) & 0xf0;
354 for (int x = 0; x < vi.width; ++x) {
355 p[x * 2] = map[p[x * 2] << 8 | ditherMap[(x & 0x0f) | _y]];
356 }
357 for (int z = 0; z < UVwidth; ++z) {
358 const int _dither = ditherMap[(z & 0x0f) | _y];
359 p[z * 4 + 1] = mapchroma[p[z * 4 + 1] << 8 | _dither];
360 p[z * 4 + 3] = mapchroma[p[z * 4 + 3] << 8 | _dither];
361 }
362 p += pitch;
363 }
364 }
365 else if (vi.IsPlanar()) {
366 if (vi.IsYUV() || vi.IsYUVA()) {
367 // planar YUV
368 if (pixelsize == 1) {
369 for (int y = 0; y < vi.height; ++y) {
370 const int _y = (y << 4) & 0xf0;
371 for (int x = 0; x < vi.width; ++x) {
372 p[x] = map[p[x] << 8 | ditherMap[(x & 0x0f) | _y]];
373 }
374 p += pitch;
375 }
376 }
377 else { // pixelsize==2
378 for (int y = 0; y < vi.height; ++y) {
379 const int _y = (y << 4) & 0xf0;
380 for (int x = 0; x < vi.width; ++x) {
381 reinterpret_cast<uint16_t *>(p)[x] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(p)[x] << 8 | ditherMap[(x & 0x0f) | _y]];
382 }
383 p += pitch;
384 }
385 }
386 const int UVpitch = frame->GetPitch(PLANAR_U);
387 const int w = frame->GetRowSize(PLANAR_U) / pixelsize;
388 const int h = frame->GetHeight(PLANAR_U);
389 p = frame->GetWritePtr(PLANAR_U);
390 BYTE* q = frame->GetWritePtr(PLANAR_V);
391 if (pixelsize == 1) {
392 for (int y = 0; y < h; ++y) {
393 const int _y = (y << 4) & 0xf0;
394 for (int x = 0; x < w; ++x) {
395 const int _dither = ditherMap[(x & 0x0f) | _y];
396 p[x] = mapchroma[p[x] << 8 | _dither];
397 q[x] = mapchroma[q[x] << 8 | _dither];
398 }
399 p += UVpitch;
400 q += UVpitch;
401 }
402 }
403 else { // pixelsize==2
404 for (int y = 0; y < h; ++y) {
405 const int _y = (y << 4) & 0xf0;
406 for (int x = 0; x < w; ++x) {
407 const int _dither = ditherMap[(x & 0x0f) | _y];
408 reinterpret_cast<uint16_t *>(p)[x] = reinterpret_cast<uint16_t *>(mapchroma)[reinterpret_cast<uint16_t *>(p)[x] << 8 | _dither];
409 reinterpret_cast<uint16_t *>(q)[x] = reinterpret_cast<uint16_t *>(mapchroma)[reinterpret_cast<uint16_t *>(q)[x] << 8 | _dither];
410 }
411 p += UVpitch;
412 q += UVpitch;
413 }
414 }
415 }
416 else {
417 // planar RGB
418 BYTE* b = frame->GetWritePtr(PLANAR_B);
419 BYTE* r = frame->GetWritePtr(PLANAR_R);
420 const int pitch_b = frame->GetPitch(PLANAR_B);
421 const int pitch_r = frame->GetPitch(PLANAR_R);
422 if (pixelsize == 1) {
423 for (int y = 0; y < vi.height; ++y) {
424 const int _y = (y << 4) & 0xf0;
425 for (int x = 0; x < vi.width; ++x) {
426 p[x] = map[p[x] << 8 | ditherMap[(x & 0x0f) | _y]];
427 b[x] = map[b[x] << 8 | ditherMap[(x & 0x0f) | _y]];
428 r[x] = map[r[x] << 8 | ditherMap[(x & 0x0f) | _y]];
429 }
430 p += pitch;
431 b += pitch_b;
432 r += pitch_r;
433 }
434 }
435 else { // pixelsize==2
436 for (int y = 0; y < vi.height; ++y) {
437 const int _y = (y << 4) & 0xf0;
438 for (int x = 0; x < vi.width; ++x) {
439 reinterpret_cast<uint16_t *>(p)[x] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(p)[x] << 8 | ditherMap[(x & 0x0f) | _y]];
440 reinterpret_cast<uint16_t *>(b)[x] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(b)[x] << 8 | ditherMap[(x & 0x0f) | _y]];
441 reinterpret_cast<uint16_t *>(r)[x] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(r)[x] << 8 | ditherMap[(x & 0x0f) | _y]];
442 }
443 p += pitch;
444 b += pitch_b;
445 r += pitch_r;
446 }
447 }
448 }
449 }
450 else if (vi.IsRGB32()) {
451 for (int y = 0; y < vi.height; ++y) {
452 const int _y = (y << 4) & 0xf0;
453 for (int x = 0; x < vi.width; ++x) {
454 const int _dither = ditherMap[(x & 0x0f) | _y];
455 p[x * 4 + 0] = map[p[x * 4 + 0] << 8 | _dither];
456 p[x * 4 + 1] = map[p[x * 4 + 1] << 8 | _dither];
457 p[x * 4 + 2] = map[p[x * 4 + 2] << 8 | _dither];
458 p[x * 4 + 3] = map[p[x * 4 + 3] << 8 | _dither];
459 }
460 p += pitch;
461 }
462 }
463 else if (vi.IsRGB24()) {
464 for (int y = 0; y < vi.height; ++y) {
465 const int _y = (y << 4) & 0xf0;
466 for (int x = 0; x < vi.width; ++x) {
467 const int _dither = ditherMap[(x & 0x0f) | _y];
468 p[x * 3 + 0] = map[p[x * 3 + 0] << 8 | _dither];
469 p[x * 3 + 1] = map[p[x * 3 + 1] << 8 | _dither];
470 p[x * 3 + 2] = map[p[x * 3 + 2] << 8 | _dither];
471 }
472 p += pitch;
473 }
474 }
475 else if (vi.IsRGB64()) {
476 for (int y = 0; y < vi.height; ++y) {
477 const int _y = (y << 4) & 0xf0;
478 for (int x = 0; x < vi.width; ++x) {
479 const int _dither = ditherMap[(x & 0x0f) | _y];
480 reinterpret_cast<uint16_t *>(p)[x * 4 + 0] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(p)[x * 4 + 0] << 8 | _dither];
481 reinterpret_cast<uint16_t *>(p)[x * 4 + 1] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(p)[x * 4 + 1] << 8 | _dither];
482 reinterpret_cast<uint16_t *>(p)[x * 4 + 2] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(p)[x * 4 + 2] << 8 | _dither];
483 reinterpret_cast<uint16_t *>(p)[x * 4 + 3] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(p)[x * 4 + 3] << 8 | _dither];
484 }
485 p += pitch;
486 }
487 }
488 else if (vi.IsRGB48()) {
489 for (int y = 0; y < vi.height; ++y) {
490 const int _y = (y << 4) & 0xf0;
491 for (int x = 0; x < vi.width; ++x) {
492 const int _dither = ditherMap[(x & 0x0f) | _y];
493 reinterpret_cast<uint16_t *>(p)[x * 3 + 0] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(p)[x * 3 + 0] << 8 | _dither];
494 reinterpret_cast<uint16_t *>(p)[x * 3 + 1] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(p)[x * 3 + 1] << 8 | _dither];
495 reinterpret_cast<uint16_t *>(p)[x * 3 + 2] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(p)[x * 3 + 2] << 8 | _dither];
496 }
497 p += pitch;
498 }
499 }
500 }
501 else { // no dithering
502
2/4
✓ Branch 120 → 121 taken 3 times.
✗ Branch 120 → 524 not taken.
✗ Branch 121 → 122 not taken.
✓ Branch 121 → 128 taken 3 times.
3 if (vi.IsYUY2()) {
503 for (int y = 0; y < vi.height; ++y) {
504 for (int x = 0; x < vi.width; ++x) {
505 p[x * 2 + 0] = map[p[x * 2 + 0]];
506 p[x * 2 + 1] = mapchroma[p[x * 2 + 1]];
507 }
508 p += pitch;
509 }
510 }
511
2/4
✓ Branch 128 → 129 taken 3 times.
✗ Branch 128 → 524 not taken.
✓ Branch 129 → 130 taken 3 times.
✗ Branch 129 → 208 not taken.
3 else if (vi.IsPlanar()) {
512
3/10
✓ Branch 130 → 131 taken 3 times.
✗ Branch 130 → 524 not taken.
✗ Branch 131 → 132 not taken.
✓ Branch 131 → 134 taken 3 times.
✗ Branch 132 → 133 not taken.
✗ Branch 132 → 524 not taken.
✗ Branch 133 → 134 not taken.
✗ Branch 133 → 135 not taken.
✓ Branch 136 → 137 taken 3 times.
✗ Branch 136 → 187 not taken.
3 if (vi.IsYUV() || vi.IsYUVA()) {
513 // planar YUV
514
2/2
✓ Branch 137 → 138 taken 2 times.
✓ Branch 137 → 144 taken 1 time.
3 if (pixelsize == 1) {
515
2/2
✓ Branch 143 → 139 taken 4 times.
✓ Branch 143 → 150 taken 2 times.
6 for (int y = 0; y < vi.height; ++y) {
516
2/2
✓ Branch 141 → 140 taken 32 times.
✓ Branch 141 → 142 taken 4 times.
36 for (int x = 0; x < vi.width; ++x) {
517 32 p[x] = map[p[x]];
518 }
519 4 p += pitch;
520 }
521 }
522 else { // pixelsize==2
523
2/2
✓ Branch 149 → 145 taken 6 times.
✓ Branch 149 → 150 taken 1 time.
7 for (int y = 0; y < vi.height; ++y) {
524
2/2
✓ Branch 147 → 146 taken 48 times.
✓ Branch 147 → 148 taken 6 times.
54 for (int x = 0; x < vi.width; ++x) {
525 48 reinterpret_cast<uint16_t *>(p)[x] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(p)[x]];
526 }
527 6 p += pitch;
528 }
529 }
530
1/2
✓ Branch 151 → 152 taken 3 times.
✗ Branch 151 → 524 not taken.
3 const int UVpitch = frame->GetPitch(PLANAR_U);
531
1/2
✓ Branch 153 → 154 taken 3 times.
✗ Branch 153 → 524 not taken.
3 p = frame->GetWritePtr(PLANAR_U);
532
1/2
✓ Branch 155 → 156 taken 3 times.
✗ Branch 155 → 524 not taken.
3 const int w = frame->GetRowSize(PLANAR_U) / pixelsize;
533
1/2
✓ Branch 157 → 158 taken 3 times.
✗ Branch 157 → 524 not taken.
3 const int h = frame->GetHeight(PLANAR_U);
534
2/2
✓ Branch 158 → 159 taken 2 times.
✓ Branch 158 → 173 taken 1 time.
3 if (pixelsize == 1) {
535
2/2
✓ Branch 164 → 160 taken 2 times.
✓ Branch 164 → 165 taken 2 times.
4 for (int y = 0; y < h; ++y) {
536
2/2
✓ Branch 162 → 161 taken 16 times.
✓ Branch 162 → 163 taken 2 times.
18 for (int x = 0; x < w; ++x) {
537 16 p[x] = mapchroma[p[x]];
538 }
539 2 p += UVpitch;
540 }
541
1/2
✓ Branch 166 → 167 taken 2 times.
✗ Branch 166 → 524 not taken.
2 p = frame->GetWritePtr(PLANAR_V);
542
2/2
✓ Branch 172 → 168 taken 2 times.
✓ Branch 172 → 522 taken 2 times.
4 for (int y = 0; y < h; ++y) {
543
2/2
✓ Branch 170 → 169 taken 16 times.
✓ Branch 170 → 171 taken 2 times.
18 for (int x = 0; x < w; ++x) {
544 16 p[x] = mapchroma[p[x]];
545 }
546 2 p += UVpitch;
547 }
548 }
549 else { // pixelsize==2
550
2/2
✓ Branch 178 → 174 taken 3 times.
✓ Branch 178 → 179 taken 1 time.
4 for (int y = 0; y < h; ++y) {
551
2/2
✓ Branch 176 → 175 taken 12 times.
✓ Branch 176 → 177 taken 3 times.
15 for (int x = 0; x < w; ++x) {
552 12 reinterpret_cast<uint16_t *>(p)[x] = reinterpret_cast<uint16_t *>(mapchroma)[reinterpret_cast<uint16_t *>(p)[x]];
553 }
554 3 p += UVpitch;
555 }
556
1/2
✓ Branch 180 → 181 taken 1 time.
✗ Branch 180 → 524 not taken.
1 p = frame->GetWritePtr(PLANAR_V);
557
2/2
✓ Branch 186 → 182 taken 3 times.
✓ Branch 186 → 522 taken 1 time.
4 for (int y = 0; y < h; ++y) {
558
2/2
✓ Branch 184 → 183 taken 12 times.
✓ Branch 184 → 185 taken 3 times.
15 for (int x = 0; x < w; ++x) {
559 12 reinterpret_cast<uint16_t *>(p)[x] = reinterpret_cast<uint16_t *>(mapchroma)[reinterpret_cast<uint16_t *>(p)[x]];
560 }
561 3 p += UVpitch;
562 }
563 }
564 }
565 else {
566 // Planar RGB
567 BYTE* b = frame->GetWritePtr(PLANAR_B);
568 BYTE* r = frame->GetWritePtr(PLANAR_R);
569 const int pitch_b = frame->GetPitch(PLANAR_B);
570 const int pitch_r = frame->GetPitch(PLANAR_R);
571 if (pixelsize == 1) {
572 for (int y = 0; y < vi.height; ++y) {
573 for (int x = 0; x < vi.width; ++x) {
574 p[x] = map[p[x]];
575 b[x] = map[b[x]];
576 r[x] = map[r[x]];
577 }
578 p += pitch;
579 b += pitch_b;
580 r += pitch_r;
581 }
582 }
583 else { // pixelsize==2
584 for (int y = 0; y < vi.height; ++y) {
585 for (int x = 0; x < vi.width; ++x) {
586 reinterpret_cast<uint16_t *>(p)[x] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(p)[x]];
587 reinterpret_cast<uint16_t *>(b)[x] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(b)[x]];
588 reinterpret_cast<uint16_t *>(r)[x] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(r)[x]];
589 }
590 p += pitch;
591 b += pitch_b;
592 r += pitch_r;
593 }
594 }
595 }
596 }
597 else if (vi.IsRGB()) {
598 // packed RGB
599 const int work_width = frame->GetRowSize() / pixelsize;
600 if (pixelsize == 1) {
601 for (int y = 0; y < vi.height; ++y) {
602 for (int x = 0; x < work_width; ++x) {
603 p[x] = map[p[x]];
604 }
605 p += pitch;
606 }
607 }
608 else { // pixelsize==2
609 for (int y = 0; y < vi.height; ++y) {
610 for (int x = 0; x < work_width; ++x) {
611 reinterpret_cast<uint16_t *>(p)[x] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(p)[x]];
612 }
613 p += pitch;
614 }
615 }
616 }
617 }
618 }
619 else {
620 // float 32 bit. only planars here
621 // no lut, realtime calculation only
622
1/2
✗ Branch 225 → 226 not taken.
✓ Branch 225 → 374 taken 1 time.
1 if (dither) {
623 if (vi.IsYUV() || vi.IsYUVA()) { // planar YUV (incl Y only)
624 // luma. with or w/o gamma
625 if (use_gamma) {
626 for (int y = 0; y < vi.height; ++y) {
627 const int _y = (y << 4) & 0xf0;
628 for (int x = 0; x < vi.width; ++x) {
629 float _dither = ditherMap_f[(x & 0x0f) | _y];
630 const float pixel = reinterpret_cast<float *>(p)[x] + _dither;
631 reinterpret_cast<float *>(p)[x] = calcPixel<false, true>(pixel);
632 }
633 p += pitch;
634 }
635 }
636 else {
637 // don't use gamma (faster)
638 for (int y = 0; y < vi.height; ++y) {
639 const int _y = (y << 4) & 0xf0;
640 for (int x = 0; x < vi.width; ++x) {
641 float _dither = ditherMap_f[(x & 0x0f) | _y];
642 const float pixel = reinterpret_cast<float *>(p)[x] + _dither;
643 reinterpret_cast<float *>(p)[x] = calcPixel<false, false>(pixel); // w/o gamma
644 }
645 p += pitch;
646 }
647 }
648 // chroma
649 if (need_chroma) {
650 const int UVpitch = frame->GetPitch(PLANAR_U);
651 const int w = frame->GetRowSize(PLANAR_U) / pixelsize;
652 const int h = frame->GetHeight(PLANAR_U);
653 p = frame->GetWritePtr(PLANAR_U);
654 BYTE* q = frame->GetWritePtr(PLANAR_V);
655 for (int y = 0; y < h; ++y) {
656 const int _y = (y << 4) & 0xf0;
657 for (int x = 0; x < w; ++x) {
658 float _dither = ditherMap_f[(x & 0x0f) | _y];
659 const float pixel_u = reinterpret_cast<float *>(p)[x] + _dither;
660 reinterpret_cast<float *>(p)[x] = calcPixel<true, false>(pixel_u);
661 const float pixel_v = reinterpret_cast<float *>(q)[x] + _dither;
662 reinterpret_cast<float *>(q)[x] = calcPixel<true, false>(pixel_v);
663 }
664 p += UVpitch;
665 q += UVpitch;
666 }
667 }
668 }
669 else if (vi.IsPlanarRGB() || vi.IsPlanarRGBA()) {
670 // planar RGB
671 BYTE* b = frame->GetWritePtr(PLANAR_B);
672 BYTE* r = frame->GetWritePtr(PLANAR_R);
673 const int pitch_b = frame->GetPitch(PLANAR_B);
674 const int pitch_r = frame->GetPitch(PLANAR_R);
675 if (use_gamma) {
676 for (int y = 0; y < vi.height; ++y) {
677 const int _y = (y << 4) & 0xf0;
678 for (int x = 0; x < vi.width; ++x) {
679 float _dither = ditherMap_f[(x & 0x0f) | _y];
680 const float pixel_p = reinterpret_cast<float *>(p)[x] + _dither; // g channel
681 reinterpret_cast<float *>(p)[x] = calcPixel<false, true>(pixel_p);
682 const float pixel_b = reinterpret_cast<float *>(b)[x] + _dither;
683 reinterpret_cast<float *>(b)[x] = calcPixel<false, true>(pixel_b);
684 const float pixel_r = reinterpret_cast<float *>(r)[x] + _dither;
685 reinterpret_cast<float *>(r)[x] = calcPixel<false, true>(pixel_r);
686 }
687 p += pitch; // g
688 b += pitch_b;
689 r += pitch_r;
690 }
691 }
692 else {
693 for (int y = 0; y < vi.height; ++y) {
694 const int _y = (y << 4) & 0xf0;
695 for (int x = 0; x < vi.width; ++x) {
696 float _dither = ditherMap_f[(x & 0x0f) | _y];
697 const float pixel_p = reinterpret_cast<float *>(p)[x] + _dither; // g channel
698 reinterpret_cast<float *>(p)[x] = calcPixel<false, false>(pixel_p);
699 const float pixel_b = reinterpret_cast<float *>(b)[x] + _dither;
700 reinterpret_cast<float *>(b)[x] = calcPixel<false, false>(pixel_b);
701 const float pixel_r = reinterpret_cast<float *>(r)[x] + _dither;
702 reinterpret_cast<float *>(r)[x] = calcPixel<false, false>(pixel_r);
703 }
704 p += pitch; // g
705 b += pitch_b;
706 r += pitch_r;
707 }
708 }
709 }
710 else {
711 // 32 bit, neither YUV(A), nor RGB(A)
712 }
713 }
714 else {
715 // no dither
716
3/10
✓ Branch 374 → 375 taken 1 time.
✗ Branch 374 → 524 not taken.
✗ Branch 375 → 376 not taken.
✓ Branch 375 → 378 taken 1 time.
✗ Branch 376 → 377 not taken.
✗ Branch 376 → 524 not taken.
✗ Branch 377 → 378 not taken.
✗ Branch 377 → 379 not taken.
✓ Branch 380 → 381 taken 1 time.
✗ Branch 380 → 441 not taken.
1 if (vi.IsYUV() || vi.IsYUVA()) { // planar YUV (incl Y only)
717 // luma. with or w/o gamma
718
1/2
✓ Branch 381 → 382 taken 1 time.
✗ Branch 381 → 398 not taken.
1 if (use_gamma) {
719
2/2
✓ Branch 397 → 383 taken 2 times.
✓ Branch 397 → 413 taken 1 time.
3 for (int y = 0; y < vi.height; ++y) {
720
2/2
✓ Branch 395 → 384 taken 10 times.
✓ Branch 395 → 396 taken 2 times.
12 for (int x = 0; x < vi.width; ++x) {
721 10 const float pixel = reinterpret_cast<float *>(p)[x];
722 20 reinterpret_cast<float *>(p)[x] = calcPixel<false, true>(pixel);
723 }
724 2 p += pitch;
725 }
726 }
727 else {
728 // don't use gamma (faster)
729 for (int y = 0; y < vi.height; ++y) {
730 for (int x = 0; x < vi.width; ++x) {
731 const float pixel = reinterpret_cast<float *>(p)[x];
732 reinterpret_cast<float *>(p)[x] = calcPixel<false, false>(pixel); // w/o gamma
733 }
734 p += pitch;
735 }
736 }
737 // chroma
738
1/2
✓ Branch 413 → 414 taken 1 time.
✗ Branch 413 → 522 not taken.
1 if (need_chroma) {
739
1/2
✓ Branch 415 → 416 taken 1 time.
✗ Branch 415 → 524 not taken.
1 const int UVpitch = frame->GetPitch(PLANAR_U);
740
1/2
✓ Branch 417 → 418 taken 1 time.
✗ Branch 417 → 524 not taken.
1 const int w = frame->GetRowSize(PLANAR_U) / pixelsize;
741
1/2
✓ Branch 419 → 420 taken 1 time.
✗ Branch 419 → 524 not taken.
1 const int h = frame->GetHeight(PLANAR_U);
742
1/2
✓ Branch 421 → 422 taken 1 time.
✗ Branch 421 → 524 not taken.
1 p = frame->GetWritePtr(PLANAR_U);
743
1/2
✓ Branch 423 → 424 taken 1 time.
✗ Branch 423 → 524 not taken.
1 BYTE* q = frame->GetWritePtr(PLANAR_V);
744
2/2
✓ Branch 440 → 425 taken 2 times.
✓ Branch 440 → 522 taken 1 time.
3 for (int y = 0; y < h; ++y) {
745
2/2
✓ Branch 438 → 426 taken 10 times.
✓ Branch 438 → 439 taken 2 times.
12 for (int x = 0; x < w; ++x) {
746 10 const float pixel_u = reinterpret_cast<float *>(p)[x];
747 10 reinterpret_cast<float *>(p)[x] = calcPixel<true, false>(pixel_u);
748 10 const float pixel_v = reinterpret_cast<float *>(q)[x];
749
1/2
✗ Branch 432 → 433 not taken.
✓ Branch 432 → 434 taken 10 times.
20 reinterpret_cast<float *>(q)[x] = calcPixel<true, false>(pixel_v);
750 }
751 2 p += UVpitch;
752 2 q += UVpitch;
753 }
754 }
755 }
756 else if (vi.IsPlanarRGB() || vi.IsPlanarRGBA()) {
757 // planar RGB
758 BYTE* b = frame->GetWritePtr(PLANAR_B);
759 BYTE* r = frame->GetWritePtr(PLANAR_R);
760 const int pitch_b = frame->GetPitch(PLANAR_B);
761 const int pitch_r = frame->GetPitch(PLANAR_R);
762 if (use_gamma) {
763 for (int y = 0; y < vi.height; ++y) {
764 for (int x = 0; x < vi.width; ++x) {
765 const float pixel_p = reinterpret_cast<float *>(p)[x]; // g channel
766 reinterpret_cast<float *>(p)[x] = calcPixel<false, true>(pixel_p);
767 const float pixel_b = reinterpret_cast<float *>(b)[x];
768 reinterpret_cast<float *>(b)[x] = calcPixel<false, true>(pixel_b);
769 const float pixel_r = reinterpret_cast<float *>(r)[x];
770 reinterpret_cast<float *>(r)[x] = calcPixel<false, true>(pixel_r);
771 }
772 p += pitch; // g
773 b += pitch_b;
774 r += pitch_r;
775 }
776 }
777 else {
778 for (int y = 0; y < vi.height; ++y) {
779 for (int x = 0; x < vi.width; ++x) {
780 const float pixel_p = reinterpret_cast<float *>(p)[x]; // g channel
781 reinterpret_cast<float *>(p)[x] = calcPixel<false, false>(pixel_p);
782 const float pixel_b = reinterpret_cast<float *>(b)[x];
783 reinterpret_cast<float *>(b)[x] = calcPixel<false, false>(pixel_b);
784 const float pixel_r = reinterpret_cast<float *>(r)[x];
785 reinterpret_cast<float *>(r)[x] = calcPixel<false, false>(pixel_r);
786 }
787 p += pitch; // g
788 b += pitch_b;
789 r += pitch_r;
790 }
791 }
792 }
793 else {
794 // 32 bit, neither YUV(A), nor RGB(A)
795 }
796 }
797 }
798 4 return frame;
799 }
800
801 AVSValue __cdecl Levels::Create(AVSValue args, void*, IScriptEnvironment* env)
802 {
803 enum { CHILD, IN_MIN, GAMMA, IN_MAX, OUT_MIN, OUT_MAX, CORING, DITHER };
804 return new Levels( args[CHILD].AsClip(), (float)args[IN_MIN].AsFloat(), (float)args[GAMMA].AsFloat(), (float)args[IN_MAX].AsFloat(),
805 (float)args[OUT_MIN].AsFloat(), (float)args[OUT_MAX].AsFloat(), args[CORING].AsBool(true), args[DITHER].AsBool(false), env );
806 }
807
808 /********************************
809 ******* RGBA Filter ******
810 ********************************/
811
812 #define READ_CONDITIONAL(plane_num, var_name, internal_name, condVarSuffix) \
813 { \
814 std::string s = "rgbadjust_" #var_name;\
815 s = s + condVarSuffix; \
816 const double t = env->GetVarDouble(s.c_str(), DBL_MIN); \
817 if (t != DBL_MIN) { \
818 config->rgba[plane_num].internal_name = t; \
819 config->rgba[plane_num].changed = true; \
820 } \
821 }
822
823 9 static void rgbadjust_read_conditional(IScriptEnvironment* env, RGBAdjustConfig* config, const char * condVarSuffix)
824 {
825
5/8
✓ Branch 4 → 5 taken 9 times.
✗ Branch 4 → 147 not taken.
✓ Branch 6 → 7 taken 9 times.
✗ Branch 6 → 150 not taken.
✓ Branch 10 → 11 taken 9 times.
✗ Branch 10 → 151 not taken.
✓ Branch 11 → 12 taken 1 time.
✓ Branch 11 → 13 taken 8 times.
18 READ_CONDITIONAL(0, r, scale, condVarSuffix);
826
4/8
✓ Branch 16 → 17 taken 9 times.
✗ Branch 16 → 154 not taken.
✓ Branch 18 → 19 taken 9 times.
✗ Branch 18 → 157 not taken.
✓ Branch 22 → 23 taken 9 times.
✗ Branch 22 → 158 not taken.
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 9 times.
18 READ_CONDITIONAL(1, g, scale, condVarSuffix);
827
4/8
✓ Branch 28 → 29 taken 9 times.
✗ Branch 28 → 161 not taken.
✓ Branch 30 → 31 taken 9 times.
✗ Branch 30 → 164 not taken.
✓ Branch 34 → 35 taken 9 times.
✗ Branch 34 → 165 not taken.
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 9 times.
18 READ_CONDITIONAL(2, b, scale, condVarSuffix);
828
4/8
✓ Branch 40 → 41 taken 9 times.
✗ Branch 40 → 168 not taken.
✓ Branch 42 → 43 taken 9 times.
✗ Branch 42 → 171 not taken.
✓ Branch 46 → 47 taken 9 times.
✗ Branch 46 → 172 not taken.
✗ Branch 47 → 48 not taken.
✓ Branch 47 → 49 taken 9 times.
18 READ_CONDITIONAL(3, a, scale, condVarSuffix);
829
830
4/8
✓ Branch 52 → 53 taken 9 times.
✗ Branch 52 → 175 not taken.
✓ Branch 54 → 55 taken 9 times.
✗ Branch 54 → 178 not taken.
✓ Branch 58 → 59 taken 9 times.
✗ Branch 58 → 179 not taken.
✗ Branch 59 → 60 not taken.
✓ Branch 59 → 61 taken 9 times.
18 READ_CONDITIONAL(0, rb, bias, condVarSuffix);
831
5/8
✓ Branch 64 → 65 taken 9 times.
✗ Branch 64 → 182 not taken.
✓ Branch 66 → 67 taken 9 times.
✗ Branch 66 → 185 not taken.
✓ Branch 70 → 71 taken 9 times.
✗ Branch 70 → 186 not taken.
✓ Branch 71 → 72 taken 1 time.
✓ Branch 71 → 73 taken 8 times.
18 READ_CONDITIONAL(1, gb, bias, condVarSuffix);
832
4/8
✓ Branch 76 → 77 taken 9 times.
✗ Branch 76 → 189 not taken.
✓ Branch 78 → 79 taken 9 times.
✗ Branch 78 → 192 not taken.
✓ Branch 82 → 83 taken 9 times.
✗ Branch 82 → 193 not taken.
✗ Branch 83 → 84 not taken.
✓ Branch 83 → 85 taken 9 times.
18 READ_CONDITIONAL(2, bb, bias, condVarSuffix);
833
4/8
✓ Branch 88 → 89 taken 9 times.
✗ Branch 88 → 196 not taken.
✓ Branch 90 → 91 taken 9 times.
✗ Branch 90 → 199 not taken.
✓ Branch 94 → 95 taken 9 times.
✗ Branch 94 → 200 not taken.
✗ Branch 95 → 96 not taken.
✓ Branch 95 → 97 taken 9 times.
18 READ_CONDITIONAL(3, ab, bias, condVarSuffix);
834
835
4/8
✓ Branch 100 → 101 taken 9 times.
✗ Branch 100 → 203 not taken.
✓ Branch 102 → 103 taken 9 times.
✗ Branch 102 → 206 not taken.
✓ Branch 106 → 107 taken 9 times.
✗ Branch 106 → 207 not taken.
✗ Branch 107 → 108 not taken.
✓ Branch 107 → 109 taken 9 times.
18 READ_CONDITIONAL(0, rg, gamma, condVarSuffix);
836
4/8
✓ Branch 112 → 113 taken 9 times.
✗ Branch 112 → 210 not taken.
✓ Branch 114 → 115 taken 9 times.
✗ Branch 114 → 213 not taken.
✓ Branch 118 → 119 taken 9 times.
✗ Branch 118 → 214 not taken.
✗ Branch 119 → 120 not taken.
✓ Branch 119 → 121 taken 9 times.
18 READ_CONDITIONAL(1, gg, gamma, condVarSuffix);
837
5/8
✓ Branch 124 → 125 taken 9 times.
✗ Branch 124 → 217 not taken.
✓ Branch 126 → 127 taken 9 times.
✗ Branch 126 → 220 not taken.
✓ Branch 130 → 131 taken 9 times.
✗ Branch 130 → 221 not taken.
✓ Branch 131 → 132 taken 1 time.
✓ Branch 131 → 133 taken 8 times.
18 READ_CONDITIONAL(2, bg, gamma, condVarSuffix);
838
4/8
✓ Branch 136 → 137 taken 9 times.
✗ Branch 136 → 224 not taken.
✓ Branch 138 → 139 taken 9 times.
✗ Branch 138 → 227 not taken.
✓ Branch 142 → 143 taken 9 times.
✗ Branch 142 → 228 not taken.
✗ Branch 143 → 144 not taken.
✓ Branch 143 → 145 taken 9 times.
18 READ_CONDITIONAL(3, ag, gamma, condVarSuffix);
839 9 }
840
841 #undef READ_CONDITIONAL
842
843
844
845 9 RGBAdjust::~RGBAdjust()
846 {
847
2/2
✓ Branch 2 → 3 taken 8 times.
✓ Branch 2 → 5 taken 1 time.
9 if (map_holder)
848
1/2
✓ Branch 3 → 4 taken 8 times.
✗ Branch 3 → 5 not taken.
8 delete[] map_holder;
849 9 }
850
851 10 void RGBAdjust::CheckAndConvertParams(RGBAdjustConfig &config, IScriptEnvironment *env)
852 {
853
4/8
✓ Branch 2 → 3 taken 10 times.
✗ Branch 2 → 6 not taken.
✓ Branch 3 → 4 taken 10 times.
✗ Branch 3 → 6 not taken.
✓ Branch 4 → 5 taken 10 times.
✗ Branch 4 → 6 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 10 times.
10 if ((config.rgba[0].gamma <= 0.0) || (config.rgba[1].gamma <= 0.0) || (config.rgba[2].gamma <= 0.0) || (config.rgba[3].gamma <= 0.0))
854 env->ThrowError("RGBAdjust: gammas must be positive");
855 10 }
856
857 60 static __inline float RGBAdjust_processPixel(const float val, const double c0, const double c1, const double c2)
858 {
859 60 const double pixel_max = 1.0;
860 60 return (float)(pow(clamp((c0 + val * c1) / pixel_max, 0.0, 1.0), c2));
861 }
862
863 29 void RGBAdjust::rgbadjust_create_lut(BYTE *lut_buf, const int plane, RGBAdjustConfig &cfg) {
864
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 29 times.
29 if (!use_lut)
865 return;
866
867 29 const int lookup_size = 1 << bits_per_pixel; // 256, 1024, 4096, 16384, 65536
868
869 void(*set_map)(BYTE*, int, int, float, const double, const double, const double);
870
2/2
✓ Branch 4 → 5 taken 3 times.
✓ Branch 4 → 7 taken 26 times.
29 if (dither) {
871 3 set_map = [](BYTE* map, int lookup_size, int bits_per_pixel, float dither_strength, const double c0, const double c1, const double c2) {
872 3 double bias_dither = -(256.0f * dither_strength - 1) / 2; // -127.5 for 8 bit, scaling because of dithershift
873 3 double pixel_max = (1 << bits_per_pixel) - 1;
874
1/2
✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 7 not taken.
3 if (bits_per_pixel == 8) {
875
2/2
✓ Branch 6 → 4 taken 196608 times.
✓ Branch 6 → 11 taken 3 times.
196611 for (int i = 0; i < lookup_size * 256; ++i) {
876 196608 int ii = (i & 0xFFFFFF00) + (int)((i & 0xFF)*dither_strength);
877 196608 map[i] = BYTE(pow(clamp((c0 * 256 + ii * c1 - bias_dither) / (double(pixel_max) * 256), 0.0, 1.0), c2) * (double)pixel_max + 0.5);
878 }
879 }
880 else {
881 for (int i = 0; i < lookup_size * 256; ++i) {
882 int ii = (i & 0xFFFFFF00) + (int)((i & 0xFF)*dither_strength);
883 reinterpret_cast<uint16_t *>(map)[i] = uint16_t(pow(clamp((c0 * 256 + ii * c1 - bias_dither) / (double(pixel_max) * 256), 0.0, 1.0), c2) * (double)pixel_max + 0.5);
884 }
885 }
886 3 };
887 }
888 else {
889 26 set_map = [](BYTE* map, int lookup_size, int bits_per_pixel, float dither_strength, const double c0, const double c1, const double c2) {
890 26 double pixel_max = (1 << bits_per_pixel) - 1;
891
2/2
✓ Branch 2 → 3 taken 19 times.
✓ Branch 2 → 7 taken 7 times.
26 if (bits_per_pixel == 8) {
892
2/2
✓ Branch 6 → 4 taken 4864 times.
✓ Branch 6 → 11 taken 19 times.
4883 for (int i = 0; i < lookup_size; ++i) { // fix of bug introduced in an earlier refactor was: i < 256 * 256
893 4864 map[i] = BYTE(pow(clamp((c0 + i * c1) / (double)pixel_max, 0.0, 1.0), c2) * double(pixel_max) + 0.5);
894 }
895 }
896 else {
897
2/2
✓ Branch 10 → 8 taken 458752 times.
✓ Branch 10 → 11 taken 7 times.
458759 for (int i = 0; i < lookup_size; ++i) { // fix of bug introduced in an earlier refactor was: i < 256 * 256
898 458752 reinterpret_cast<uint16_t *>(map)[i] = uint16_t(pow(clamp((c0 + i * c1) / (double)pixel_max, 0.0, 1.0), c2) * double(pixel_max) + 0.5);
899 }
900 }
901 26 };
902 }
903
904 29 set_map(lut_buf, lookup_size, bits_per_pixel, dither_strength, cfg.rgba[plane].bias, cfg.rgba[plane].scale, 1 / cfg.rgba[plane].gamma);
905 }
906
907 9 RGBAdjust::RGBAdjust(PClip _child, double r, double g, double b, double a,
908 double rb, double gb, double bb, double ab,
909 double rg, double gg, double bg, double ag,
910 9 bool _analyze, bool _dither, bool _conditional, const char *_condVarSuffix, IScriptEnvironment* env)
911
2/4
✓ Branch 2 → 3 taken 9 times.
✗ Branch 2 → 54 not taken.
✓ Branch 3 → 4 taken 9 times.
✗ Branch 3 → 52 not taken.
9 : GenericVideoFilter(_child), analyze(_analyze), dither(_dither), condVarSuffix(_condVarSuffix)
912 {
913 // one buffer for all maps
914 9 map_holder = nullptr;
915
916
2/4
✓ Branch 5 → 6 taken 9 times.
✗ Branch 5 → 55 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 9 times.
9 if (!vi.IsRGB())
917 env->ThrowError("RGBAdjust requires RGB input");
918
919 9 config.rgba[0].scale = r;
920 9 config.rgba[1].scale = g;
921 9 config.rgba[2].scale = b;
922 9 config.rgba[3].scale = a;
923 // bias
924 9 config.rgba[0].bias = rb;
925 9 config.rgba[1].bias = gb;
926 9 config.rgba[2].bias = bb;
927 9 config.rgba[3].bias = ab;
928 // gammas
929 9 config.rgba[0].gamma = rg;
930 9 config.rgba[1].gamma = gg;
931 9 config.rgba[2].gamma = bg;
932 9 config.rgba[3].gamma = ag;
933
934 9 config.rgba[0].changed = false;
935 9 config.rgba[1].changed = false;
936 9 config.rgba[2].changed = false;
937 9 config.rgba[3].changed = false;
938
939
1/2
✓ Branch 8 → 9 taken 9 times.
✗ Branch 8 → 55 not taken.
9 CheckAndConvertParams(config, env);
940
941
1/2
✓ Branch 9 → 10 taken 9 times.
✗ Branch 9 → 55 not taken.
9 pixelsize = vi.ComponentSize();
942
1/2
✓ Branch 10 → 11 taken 9 times.
✗ Branch 10 → 55 not taken.
9 bits_per_pixel = vi.BitsPerComponent(); // 8,10..16
943
944 9 if (pixelsize == 4) {
945 // dither parameter is silently ignored
946 // if (dither) env->ThrowError("RGBAdjust: cannot 'dither' a 32bit float video");
947 }
948 // No lookup for float. todo: slow on-the-fly realtime calculation
949
950
2/2
✓ Branch 12 → 13 taken 6 times.
✓ Branch 12 → 14 taken 3 times.
9 real_lookup_size = (pixelsize == 1) ? 256 : 65536; // avoids lut overflow in case of non-standard content of a 10 bit clip
951
2/2
✓ Branch 15 → 16 taken 8 times.
✓ Branch 15 → 17 taken 1 time.
9 max_pixel_value = (pixelsize == 4) ? 255 : (1 << bits_per_pixel) - 1; // n/a for float formats
952 9 dither_strength = 1.0f; // fixed, not used
953
954 9 use_lut = bits_per_pixel != 32; // for float: realtime (todo)
955
956
2/2
✓ Branch 18 → 19 taken 1 time.
✓ Branch 18 → 20 taken 8 times.
9 if (!use_lut)
957 1 dither = false;
958
959
2/2
✓ Branch 20 → 21 taken 8 times.
✓ Branch 20 → 51 taken 1 time.
9 if(use_lut) {
960
8/12
✓ Branch 21 → 22 taken 8 times.
✗ Branch 21 → 55 not taken.
✓ Branch 22 → 23 taken 3 times.
✓ Branch 22 → 27 taken 5 times.
✓ Branch 23 → 24 taken 3 times.
✗ Branch 23 → 55 not taken.
✓ Branch 24 → 25 taken 3 times.
✗ Branch 24 → 27 not taken.
✓ Branch 25 → 26 taken 3 times.
✗ Branch 25 → 55 not taken.
✓ Branch 26 → 27 taken 1 time.
✓ Branch 26 → 28 taken 2 times.
8 number_of_maps = (vi.IsRGB24() || vi.IsRGB48() || vi.IsPlanarRGB()) ? 3 : 4;
961 8 int one_bufsize = pixelsize * real_lookup_size;
962
2/2
✓ Branch 29 → 30 taken 1 time.
✓ Branch 29 → 31 taken 7 times.
8 if (dither) one_bufsize *= 256;
963
964
1/2
✓ Branch 31 → 32 taken 8 times.
✗ Branch 31 → 55 not taken.
8 map_holder = new uint8_t[one_bufsize * number_of_maps];
965 /*
966 // left here intentionally:
967 // for some reason, AtExit does not get called from within ScriptClip, causing no free thus memory leak
968 // We are using new here and delete in destructor
969 static_cast<uint8_t*>(env->Allocate(one_bufsize * number_of_maps, 16, AVS_NORMAL_ALLOC));
970 if (!mapR)
971 env->ThrowError("RGBAdjust: Could not reserve memory.");
972 env->AtExit(free_buffer, mapR);
973 */
974
3/4
✓ Branch 32 → 33 taken 2 times.
✓ Branch 32 → 44 taken 6 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 44 taken 2 times.
8 if(bits_per_pixel>8 && bits_per_pixel<16) // make lut table safe for 10-14 bit garbage
975 std::fill_n(map_holder, one_bufsize * number_of_maps, 0); // 8 and 16 bit fully overwrites
976 8 maps[0] = map_holder;
977 8 maps[1] = maps[0] + one_bufsize;
978 8 maps[2] = maps[1] + one_bufsize;
979
2/2
✓ Branch 44 → 45 taken 2 times.
✓ Branch 44 → 46 taken 6 times.
8 maps[3] = number_of_maps == 4 ? maps[2] + one_bufsize : nullptr;
980
981
2/2
✓ Branch 50 → 48 taken 26 times.
✓ Branch 50 → 51 taken 8 times.
34 for (int plane = 0; plane < number_of_maps; plane++) {
982
1/2
✓ Branch 48 → 49 taken 26 times.
✗ Branch 48 → 55 not taken.
26 rgbadjust_create_lut(maps[plane], plane, config);
983 }
984 }
985 9 }
986
987 template<typename pixel_t>
988 static void fill_accum_rgb_planar_c(const BYTE *srcpR, const BYTE* srcpG, const BYTE* srcpB, int pitch,
989 unsigned int *accum_r, unsigned int *accum_g, unsigned int *accum_b,
990 int width, int height, int max_pixel_value) {
991 for (int y = 0; y < height; y++) {
992 for (int x = 0; x < width; x++) {
993 int r = reinterpret_cast<const pixel_t*>(srcpR)[x];
994 int g = reinterpret_cast<const pixel_t*>(srcpG)[x];
995 int b = reinterpret_cast<const pixel_t*>(srcpB)[x];
996 if constexpr (sizeof(pixel_t) != 1) {
997 if (r > max_pixel_value) r = max_pixel_value;
998 if (g > max_pixel_value) g = max_pixel_value;
999 if (b > max_pixel_value) b = max_pixel_value;
1000 }
1001 accum_r[r]++;
1002 accum_g[g]++;
1003 accum_b[b]++;
1004 }
1005 srcpR += pitch;
1006 srcpG += pitch;
1007 srcpB += pitch;
1008 }
1009 }
1010
1011 static void fill_accum_rgb_planar_float_c(const BYTE* srcpR, const BYTE* srcpG, const BYTE* srcpB, int pitch,
1012 unsigned int* accum_r, unsigned int* accum_g, unsigned int* accum_b,
1013 int width, int height, RGBStats &rgbplanedata) {
1014
1015 for (int i = 0; i < 3; i++) {
1016 rgbplanedata.data[i].real_max = std::numeric_limits<float>::min();
1017 rgbplanedata.data[i].real_min = std::numeric_limits<float>::max();
1018 rgbplanedata.data[i].sum = 0.0;
1019 }
1020
1021 for (int y = 0; y < height; y++) {
1022 for (int x = 0; x < width; x++) {
1023 // convert range 0..1 to 0..65535 for loose_min/max fake histogram
1024 float r = reinterpret_cast<const float*>(srcpR)[x];
1025 float g = reinterpret_cast<const float*>(srcpG)[x];
1026 float b = reinterpret_cast<const float*>(srcpB)[x];
1027 int ri = (int)(clamp(r * 65535.0f + 0.5f, 0.0f, 65535.0f));
1028 int gi = (int)(clamp(g * 65535.0f + 0.5f, 0.0f, 65535.0f));
1029 int bi = (int)(clamp(b * 65535.0f + 0.5f, 0.0f, 65535.0f));
1030 if (r > rgbplanedata.data[0].real_max) rgbplanedata.data[0].real_max = r;
1031 if (r < rgbplanedata.data[0].real_min) rgbplanedata.data[0].real_min = r;
1032 rgbplanedata.data[0].sum += r;
1033 if (g > rgbplanedata.data[1].real_max) rgbplanedata.data[1].real_max = g;
1034 if (g < rgbplanedata.data[1].real_min) rgbplanedata.data[1].real_min = g;
1035 rgbplanedata.data[1].sum += g;
1036 if (b > rgbplanedata.data[2].real_max) rgbplanedata.data[2].real_max = b;
1037 if (b < rgbplanedata.data[2].real_min) rgbplanedata.data[2].real_min = b;
1038 rgbplanedata.data[2].sum += b;
1039 accum_r[ri]++;
1040 accum_g[gi]++;
1041 accum_b[bi]++;
1042 }
1043 srcpR += pitch;
1044 srcpG += pitch;
1045 srcpB += pitch;
1046 }
1047 }
1048
1049 template<typename pixel_t>
1050 1 static void fill_accum_rgb_packed_c(const BYTE *srcp, int pitch,
1051 unsigned int *accum_r, unsigned int *accum_g, unsigned int *accum_b,
1052 int work_width, int height, int pixel_step) {
1053
2/4
void fill_accum_rgb_packed_c<unsigned char>(unsigned char const*, int, unsigned int*, unsigned int*, unsigned int*, int, int, int):
✓ Branch 7 → 3 taken 120 times.
✓ Branch 7 → 8 taken 1 time.
void fill_accum_rgb_packed_c<unsigned short>(unsigned char const*, int, unsigned int*, unsigned int*, unsigned int*, int, int, int):
✗ Branch 7 → 3 not taken.
✗ Branch 7 → 8 not taken.
121 for (int y = 0; y < height; y++) {
1054
2/4
void fill_accum_rgb_packed_c<unsigned char>(unsigned char const*, int, unsigned int*, unsigned int*, unsigned int*, int, int, int):
✓ Branch 5 → 4 taken 38400 times.
✓ Branch 5 → 6 taken 120 times.
void fill_accum_rgb_packed_c<unsigned short>(unsigned char const*, int, unsigned int*, unsigned int*, unsigned int*, int, int, int):
✗ Branch 5 → 4 not taken.
✗ Branch 5 → 6 not taken.
38520 for (int x = 0; x < work_width; x += pixel_step) {
1055 38400 accum_r[reinterpret_cast<const pixel_t *>(srcp)[x + 2]]++;
1056 38400 accum_g[reinterpret_cast<const pixel_t *>(srcp)[x + 1]]++;
1057 38400 accum_b[reinterpret_cast<const pixel_t *>(srcp)[x + 0]]++;
1058 }
1059 120 srcp += pitch;
1060 }
1061 1 }
1062
1063 template<typename pixel_t, int pixel_step, bool dither>
1064 7 static void apply_map_rgb_packed_c(BYTE *dstp8, int pitch,
1065 BYTE *mapR, BYTE *mapG, BYTE *mapB, BYTE *mapA,
1066 int width, int height)
1067 {
1068 7 int _y = 0;
1069 7 int _dither = 0;
1070 7 pixel_t *dstp = reinterpret_cast<pixel_t *>(dstp8);
1071 7 pitch /= sizeof(pixel_t);
1072
1073
8/16
void apply_map_rgb_packed_c<unsigned char, 3, false>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✓ Branch 7 → 3 taken 128 times.
✓ Branch 7 → 8 taken 4 times.
void apply_map_rgb_packed_c<unsigned char, 3, true>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✓ Branch 7 → 3 taken 3 times.
✓ Branch 7 → 8 taken 1 time.
void apply_map_rgb_packed_c<unsigned char, 4, false>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✓ Branch 7 → 3 taken 2 times.
✓ Branch 7 → 8 taken 1 time.
void apply_map_rgb_packed_c<unsigned char, 4, true>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 7 → 3 not taken.
✗ Branch 7 → 8 not taken.
void apply_map_rgb_packed_c<unsigned short, 3, false>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 7 → 3 not taken.
✗ Branch 7 → 8 not taken.
void apply_map_rgb_packed_c<unsigned short, 3, true>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 7 → 3 not taken.
✗ Branch 7 → 8 not taken.
void apply_map_rgb_packed_c<unsigned short, 4, false>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✓ Branch 7 → 3 taken 2 times.
✓ Branch 7 → 8 taken 1 time.
void apply_map_rgb_packed_c<unsigned short, 4, true>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 7 → 3 not taken.
✗ Branch 7 → 8 not taken.
142 for (int y = 0; y < height; y++) {
1074 if(dither)
1075 3 _y = (y << 4) & 0xf0;
1076
8/16
void apply_map_rgb_packed_c<unsigned char, 3, false>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✓ Branch 5 → 4 taken 38446 times.
✓ Branch 5 → 6 taken 128 times.
void apply_map_rgb_packed_c<unsigned char, 3, true>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✓ Branch 5 → 4 taken 21 times.
✓ Branch 5 → 6 taken 3 times.
void apply_map_rgb_packed_c<unsigned char, 4, false>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✓ Branch 5 → 4 taken 16 times.
✓ Branch 5 → 6 taken 2 times.
void apply_map_rgb_packed_c<unsigned char, 4, true>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 5 → 4 not taken.
✗ Branch 5 → 6 not taken.
void apply_map_rgb_packed_c<unsigned short, 3, false>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 5 → 4 not taken.
✗ Branch 5 → 6 not taken.
void apply_map_rgb_packed_c<unsigned short, 3, true>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 5 → 4 not taken.
✗ Branch 5 → 6 not taken.
void apply_map_rgb_packed_c<unsigned short, 4, false>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✓ Branch 5 → 4 taken 6 times.
✓ Branch 5 → 6 taken 2 times.
void apply_map_rgb_packed_c<unsigned short, 4, true>(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 5 → 4 not taken.
✗ Branch 5 → 6 not taken.
38624 for (int x = 0; x < width; x++) {
1077 if (dither)
1078 21 _dither = ditherMap[(x & 0x0f) | _y];
1079 38489 dstp[x * pixel_step + 0] = reinterpret_cast<pixel_t *>(mapB)[dither ? dstp[x * pixel_step + 0] << 8 | _dither : dstp[x * pixel_step + 0]];
1080 38489 dstp[x * pixel_step + 1] = reinterpret_cast<pixel_t *>(mapG)[dither ? dstp[x * pixel_step + 1] << 8 | _dither : dstp[x * pixel_step + 1]];
1081 38489 dstp[x * pixel_step + 2] = reinterpret_cast<pixel_t *>(mapR)[dither ? dstp[x * pixel_step + 2] << 8 | _dither : dstp[x * pixel_step + 2]];
1082 if constexpr(pixel_step == 4)
1083 22 dstp[x * pixel_step + 3] = reinterpret_cast<pixel_t *>(mapA)[dither ? dstp[x * pixel_step + 3] << 8 | _dither : dstp[x * pixel_step + 3]];
1084 }
1085 135 dstp += pitch;
1086 }
1087 7 }
1088
1089 template<typename pixel_t, bool hasAlpha, bool dither>
1090 1 static void apply_map_rgb_planar_c(BYTE *dstpR8, BYTE *dstpG8, BYTE *dstpB8, BYTE *dstpA8, int pitch,
1091 BYTE *mapR, BYTE *mapG, BYTE *mapB, BYTE *mapA,
1092 int width, int height)
1093 {
1094 1 int _y = 0;
1095 1 int _dither = 0;
1096 1 pixel_t *dstpR = reinterpret_cast<pixel_t *>(dstpR8);
1097 1 pixel_t *dstpG = reinterpret_cast<pixel_t *>(dstpG8);
1098 1 pixel_t *dstpB = reinterpret_cast<pixel_t *>(dstpB8);
1099 1 pixel_t *dstpA = reinterpret_cast<pixel_t *>(dstpA8);
1100 1 pitch /= sizeof(pixel_t);
1101
1102
2/16
void apply_map_rgb_planar_c<unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 9 → 3 not taken.
✗ Branch 9 → 10 not taken.
void apply_map_rgb_planar_c<unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 9 → 3 not taken.
✗ Branch 9 → 10 not taken.
void apply_map_rgb_planar_c<unsigned char, true, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 7 → 3 not taken.
✗ Branch 7 → 8 not taken.
void apply_map_rgb_planar_c<unsigned char, true, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 7 → 3 not taken.
✗ Branch 7 → 8 not taken.
void apply_map_rgb_planar_c<unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✓ Branch 9 → 3 taken 3 times.
✓ Branch 9 → 10 taken 1 time.
void apply_map_rgb_planar_c<unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 9 → 3 not taken.
✗ Branch 9 → 10 not taken.
void apply_map_rgb_planar_c<unsigned short, true, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 7 → 3 not taken.
✗ Branch 7 → 8 not taken.
void apply_map_rgb_planar_c<unsigned short, true, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 7 → 3 not taken.
✗ Branch 7 → 8 not taken.
4 for (int y = 0; y < height; y++) {
1103 if(dither)
1104 _y = (y << 4) & 0xf0;
1105
2/16
void apply_map_rgb_planar_c<unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 6 → 4 not taken.
✗ Branch 6 → 7 not taken.
void apply_map_rgb_planar_c<unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 6 → 4 not taken.
✗ Branch 6 → 7 not taken.
void apply_map_rgb_planar_c<unsigned char, true, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 5 → 4 not taken.
✗ Branch 5 → 6 not taken.
void apply_map_rgb_planar_c<unsigned char, true, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 5 → 4 not taken.
✗ Branch 5 → 6 not taken.
void apply_map_rgb_planar_c<unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✓ Branch 6 → 4 taken 15 times.
✓ Branch 6 → 7 taken 3 times.
void apply_map_rgb_planar_c<unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 6 → 4 not taken.
✗ Branch 6 → 7 not taken.
void apply_map_rgb_planar_c<unsigned short, true, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 5 → 4 not taken.
✗ Branch 5 → 6 not taken.
void apply_map_rgb_planar_c<unsigned short, true, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int):
✗ Branch 5 → 4 not taken.
✗ Branch 5 → 6 not taken.
18 for (int x = 0; x < width; x++) {
1106 if (dither)
1107 _dither = ditherMap[(x & 0x0f) | _y];
1108 15 reinterpret_cast<pixel_t *>(dstpG)[x] = reinterpret_cast<pixel_t *>(mapG)[dither ? dstpG[x] << 8 | _dither : dstpG[x]];
1109 15 reinterpret_cast<pixel_t *>(dstpB)[x] = reinterpret_cast<pixel_t *>(mapB)[dither ? dstpB[x] << 8 | _dither : dstpB[x]];
1110 15 reinterpret_cast<pixel_t *>(dstpR)[x] = reinterpret_cast<pixel_t *>(mapR)[dither ? dstpR[x] << 8 | _dither : dstpR[x]];
1111 if(hasAlpha)
1112 reinterpret_cast<pixel_t *>(dstpA)[x] = reinterpret_cast<pixel_t *>(mapA)[dither ? dstpA[x] << 8 | _dither : dstpA[x]];
1113 }
1114 3 dstpG += pitch; dstpB += pitch; dstpR += pitch;
1115 if(hasAlpha)
1116 dstpA += pitch;
1117 }
1118 1 }
1119
1120
1121 9 PVideoFrame __stdcall RGBAdjust::GetFrame(int n, IScriptEnvironment* env)
1122 {
1123
1/2
✓ Branch 3 → 4 taken 9 times.
✗ Branch 3 → 229 not taken.
9 PVideoFrame frame = child->GetFrame(n, env);
1124
1/2
✓ Branch 4 → 5 taken 9 times.
✗ Branch 4 → 227 not taken.
9 env->MakeWritable(&frame);
1125
1/2
✓ Branch 6 → 7 taken 9 times.
✗ Branch 6 → 227 not taken.
9 BYTE* p = frame->GetWritePtr();
1126
1/2
✓ Branch 8 → 9 taken 9 times.
✗ Branch 8 → 227 not taken.
9 const int pitch = frame->GetPitch();
1127
1128 9 int w = vi.width;
1129 9 int h = vi.height;
1130
1131 9 RGBAdjustConfig local_config = config;
1132
1133 // Read conditional variables
1134 9 local_config.rgba[0].changed = false;
1135 9 local_config.rgba[1].changed = false;
1136 9 local_config.rgba[2].changed = false;
1137 9 local_config.rgba[3].changed = false;
1138
1/2
✓ Branch 9 → 10 taken 9 times.
✗ Branch 9 → 227 not taken.
9 rgbadjust_read_conditional(env, &local_config, condVarSuffix);
1139
1140 9 BYTE *maps_live[4] = { nullptr };
1141 9 BYTE *maps_local[4] = { nullptr }; // for local lut table allocation, don't overwrite common buffer
1142
2/2
✓ Branch 12 → 11 taken 36 times.
✓ Branch 12 → 13 taken 9 times.
45 for (int i = 0; i < 4; i++)
1143 36 maps_live[i] = maps[i];
1144
1145
5/8
✓ Branch 13 → 14 taken 8 times.
✓ Branch 13 → 17 taken 1 time.
✓ Branch 14 → 15 taken 8 times.
✗ Branch 14 → 17 not taken.
✓ Branch 15 → 16 taken 8 times.
✗ Branch 15 → 17 not taken.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 25 taken 8 times.
9 if (local_config.rgba[0].changed || local_config.rgba[1].changed || local_config.rgba[2].changed || local_config.rgba[3].changed) {
1146
1/2
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 227 not taken.
1 CheckAndConvertParams(local_config, env);
1147
1/2
✓ Branch 18 → 19 taken 1 time.
✗ Branch 18 → 25 not taken.
1 if (use_lut) {
1148
2/2
✓ Branch 24 → 20 taken 3 times.
✓ Branch 24 → 25 taken 1 time.
4 for (int plane = 0; plane < (int)number_of_maps; plane++) {
1149 // recalculate plane LUT only if changed
1150
1/2
✓ Branch 20 → 21 taken 3 times.
✗ Branch 20 → 23 not taken.
3 if (local_config.rgba[plane].changed)
1151 {
1152
1/2
✓ Branch 21 → 22 taken 3 times.
✗ Branch 21 → 227 not taken.
3 maps_local[plane] = new BYTE[pixelsize * real_lookup_size];
1153 3 maps_live[plane] = maps_local[plane]; // use our new local lut
1154
1/2
✓ Branch 22 → 23 taken 3 times.
✗ Branch 22 → 227 not taken.
3 rgbadjust_create_lut(maps_live[plane], plane, local_config);
1155 }
1156 }
1157 }
1158 }
1159
1160
2/2
✓ Branch 25 → 26 taken 1 time.
✓ Branch 25 → 52 taken 8 times.
9 if (dither) {
1161
2/4
✓ Branch 26 → 27 taken 1 time.
✗ Branch 26 → 227 not taken.
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 1 time.
1 if (vi.IsRGB32())
1162 apply_map_rgb_packed_c<uint8_t, 4, true>(p, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1163
2/4
✓ Branch 29 → 30 taken 1 time.
✗ Branch 29 → 227 not taken.
✓ Branch 30 → 31 taken 1 time.
✗ Branch 30 → 32 not taken.
1 else if(vi.IsRGB24())
1164 1 apply_map_rgb_packed_c<uint8_t, 3, true>(p, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1165 else if(vi.IsRGB64())
1166 apply_map_rgb_packed_c<uint16_t, 4, true>(p, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1167 else if(vi.IsRGB48())
1168 apply_map_rgb_packed_c<uint16_t, 3, true>(p, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1169 else {
1170 // Planar RGB
1171 bool hasAlpha = vi.IsPlanarRGBA();
1172 BYTE *p_g = p;
1173 BYTE *p_b = frame->GetWritePtr(PLANAR_B);
1174 BYTE *p_r = frame->GetWritePtr(PLANAR_R);
1175 BYTE *p_a = frame->GetWritePtr(PLANAR_A);
1176 // no float support
1177 if(pixelsize==1) {
1178 if(hasAlpha)
1179 apply_map_rgb_planar_c<uint8_t, true, true>(p_r, p_g, p_b, p_a, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1180 else
1181 apply_map_rgb_planar_c<uint8_t, false, true>(p_r, p_g, p_b, p_a, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1182 }
1183 else {
1184 if(hasAlpha)
1185 apply_map_rgb_planar_c<uint16_t, true, true>(p_r, p_g, p_b, p_a, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1186 else
1187 apply_map_rgb_planar_c<uint16_t, false, true>(p_r, p_g, p_b, p_a, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1188 }
1189 }
1190 }
1191 else {
1192 // no dither
1193
3/4
✓ Branch 52 → 53 taken 8 times.
✗ Branch 52 → 227 not taken.
✓ Branch 53 → 54 taken 1 time.
✓ Branch 53 → 55 taken 7 times.
8 if (vi.IsRGB32())
1194 1 apply_map_rgb_packed_c<uint8_t, 4, false>(p, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1195
3/4
✓ Branch 55 → 56 taken 7 times.
✗ Branch 55 → 227 not taken.
✓ Branch 56 → 57 taken 4 times.
✓ Branch 56 → 58 taken 3 times.
7 else if(vi.IsRGB24())
1196 4 apply_map_rgb_packed_c<uint8_t, 3, false>(p, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1197
3/4
✓ Branch 58 → 59 taken 3 times.
✗ Branch 58 → 227 not taken.
✓ Branch 59 → 60 taken 1 time.
✓ Branch 59 → 61 taken 2 times.
3 else if(vi.IsRGB64())
1198 1 apply_map_rgb_packed_c<uint16_t, 4, false>(p, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1199
2/4
✓ Branch 61 → 62 taken 2 times.
✗ Branch 61 → 227 not taken.
✗ Branch 62 → 63 not taken.
✓ Branch 62 → 64 taken 2 times.
2 else if(vi.IsRGB48())
1200 apply_map_rgb_packed_c<uint16_t, 3, false>(p, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1201 else {
1202 // Planar RGB
1203
1/2
✓ Branch 64 → 65 taken 2 times.
✗ Branch 64 → 227 not taken.
2 bool hasAlpha = vi.IsPlanarRGBA();
1204 2 BYTE *p_g = p;
1205
1/2
✓ Branch 66 → 67 taken 2 times.
✗ Branch 66 → 227 not taken.
2 BYTE *p_b = frame->GetWritePtr(PLANAR_B);
1206
1/2
✓ Branch 68 → 69 taken 2 times.
✗ Branch 68 → 227 not taken.
2 BYTE *p_r = frame->GetWritePtr(PLANAR_R);
1207
1/2
✓ Branch 70 → 71 taken 2 times.
✗ Branch 70 → 227 not taken.
2 BYTE *p_a = frame->GetWritePtr(PLANAR_A);
1208 // no float support
1209
1/2
✗ Branch 71 → 72 not taken.
✓ Branch 71 → 75 taken 2 times.
2 if(pixelsize==1) {
1210 if(hasAlpha)
1211 apply_map_rgb_planar_c<uint8_t, true, false>(p_r, p_g, p_b, p_a, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1212 else
1213 apply_map_rgb_planar_c<uint8_t, false, false>(p_r, p_g, p_b, p_a, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1214 }
1215
2/2
✓ Branch 75 → 76 taken 1 time.
✓ Branch 75 → 79 taken 1 time.
2 else if(pixelsize==2) {
1216
1/2
✗ Branch 76 → 77 not taken.
✓ Branch 76 → 78 taken 1 time.
1 if(hasAlpha)
1217 apply_map_rgb_planar_c<uint16_t, true, false>(p_r, p_g, p_b, p_a, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1218 else
1219 1 apply_map_rgb_planar_c<uint16_t, false, false>(p_r, p_g, p_b, p_a, pitch, maps_live[0], maps_live[1], maps_live[2], maps_live[3], w, h);
1220 }
1221 else {
1222 // 32 bit float, no dither
1223 1 const int planesRGB_RgbaOrder[4] = { PLANAR_R, PLANAR_G, PLANAR_B, PLANAR_A };
1224 1 const int *planes = planesRGB_RgbaOrder;
1225
1226
3/4
✓ Branch 92 → 93 taken 5 times.
✗ Branch 92 → 94 not taken.
✓ Branch 95 → 80 taken 4 times.
✓ Branch 95 → 96 taken 1 time.
5 for (int cplane = 0; cplane < (hasAlpha ? 4 : 3); cplane++) {
1227 4 RGBAdjustPlaneConfig x = local_config.rgba[cplane];
1228 4 const double scale = x.scale;
1229 4 const double bias = x.bias;
1230 4 const double gamma = 1 / x.gamma;
1231 4 int plane = planes[cplane];
1232
1/2
✓ Branch 81 → 82 taken 4 times.
✗ Branch 81 → 223 not taken.
4 float* dstp = reinterpret_cast<float *>(frame->GetWritePtr(plane));
1233
1/2
✓ Branch 83 → 84 taken 4 times.
✗ Branch 83 → 223 not taken.
4 int pitch = frame->GetPitch(plane) / sizeof(float);
1234
2/2
✓ Branch 90 → 85 taken 12 times.
✓ Branch 90 → 91 taken 4 times.
16 for (int y = 0; y < h; y++) {
1235
2/2
✓ Branch 88 → 86 taken 60 times.
✓ Branch 88 → 89 taken 12 times.
72 for (int x = 0; x < w; x++) {
1236
1/2
✓ Branch 86 → 87 taken 60 times.
✗ Branch 86 → 223 not taken.
60 dstp[x] = RGBAdjust_processPixel(dstp[x], bias, scale, gamma);
1237 }
1238 12 dstp += pitch;
1239 }
1240 }
1241 }
1242 }
1243 }
1244
1245
3/4
✓ Branch 97 → 98 taken 8 times.
✓ Branch 97 → 105 taken 1 time.
✓ Branch 98 → 99 taken 8 times.
✗ Branch 98 → 105 not taken.
9 if (use_lut && conditional) {
1246
2/2
✓ Branch 104 → 100 taken 32 times.
✓ Branch 104 → 105 taken 8 times.
40 for(int i = 0; i<4; i++)
1247
3/4
✓ Branch 100 → 101 taken 3 times.
✓ Branch 100 → 103 taken 29 times.
✓ Branch 101 → 102 taken 3 times.
✗ Branch 101 → 103 not taken.
32 if (maps_local[i]) delete[] maps_local[i];
1248 }
1249
1250
2/2
✓ Branch 105 → 106 taken 1 time.
✓ Branch 105 → 221 taken 8 times.
9 if (analyze) {
1251
1/2
✓ Branch 107 → 108 taken 1 time.
✗ Branch 107 → 227 not taken.
1 const int w = frame->GetRowSize() / pixelsize;
1252
1/2
✓ Branch 109 → 110 taken 1 time.
✗ Branch 109 → 227 not taken.
1 const int h = frame->GetHeight();
1253
1254
1/2
✓ Branch 110 → 111 taken 1 time.
✗ Branch 110 → 112 not taken.
1 const int analyze_lookup_size = pixelsize == 4 ? 1 << 16 : 1 << bits_per_pixel; // 32 bit float is quantized to 16 bits
1255 1 const int max_pixel_value_analyze = analyze_lookup_size - 1;
1256
1257 // allocate 3x bufsize for R. G and B will share it
1258
1/2
✓ Branch 113 → 114 taken 1 time.
✗ Branch 113 → 227 not taken.
1 auto accum_r = static_cast<uint32_t*>(env->Allocate(analyze_lookup_size * sizeof(uint32_t) * 3, 16, AVS_NORMAL_ALLOC));
1259 1 auto accum_g = accum_r + analyze_lookup_size;
1260 1 auto accum_b = accum_g + analyze_lookup_size;
1261
1/2
✗ Branch 114 → 115 not taken.
✓ Branch 114 → 116 taken 1 time.
1 if (!accum_r)
1262 env->ThrowError("RGBAdjust: Could not reserve memory.");
1263
1264
2/2
✓ Branch 118 → 117 taken 256 times.
✓ Branch 118 → 119 taken 1 time.
257 for (int i = 0; i < analyze_lookup_size; i++) {
1265 256 accum_r[i] = 0;
1266 256 accum_g[i] = 0;
1267 256 accum_b[i] = 0;
1268 }
1269
1270 1 const int pixels = vi.width * vi.height;
1271
1272
1/2
✗ Branch 119 → 120 not taken.
✓ Branch 119 → 151 taken 1 time.
1 if (bits_per_pixel == 32) {
1273 RGBStats rgbplanedata;
1274 const BYTE* p_g = frame->GetReadPtr(PLANAR_G);;
1275 const BYTE* p_b = frame->GetReadPtr(PLANAR_B);
1276 const BYTE* p_r = frame->GetReadPtr(PLANAR_R);
1277 fill_accum_rgb_planar_float_c(p_r, p_g, p_b, pitch, accum_r, accum_g, accum_b, w, h, rgbplanedata);
1278
1279 double avg_r = rgbplanedata.data[0].sum / pixels;
1280 double avg_g = rgbplanedata.data[1].sum / pixels;
1281 double avg_b = rgbplanedata.data[2].sum / pixels;
1282
1283 int Amin_r = 0, Amin_g = 0, Amin_b = 0;
1284 int Amax_r = 0, Amax_g = 0, Amax_b = 0;
1285 bool Ahit_minr = false, Ahit_ming = false, Ahit_minb = false;
1286 bool Ahit_maxr = false, Ahit_maxg = false, Ahit_maxb = false;
1287 int At_256 = (pixels + 128) / 256; // When 1/256th of all pixels have been reached, trigger "Loose min/max"
1288
1289 double st_r = 0, st_g = 0, st_b = 0;
1290
1291 for (int i = 0; i < analyze_lookup_size; i++) {
1292 double i_float = i / 65535.0;
1293 st_r += accum_r[i] * (i_float - avg_r) * (i_float - avg_r);
1294 st_g += accum_g[i] * (i_float - avg_g) * (i_float - avg_g);
1295 st_b += accum_b[i] * (i_float - avg_b) * (i_float - avg_b);
1296
1297 // loose min
1298 if (!Ahit_minr) { Amin_r += accum_r[i]; if (Amin_r > At_256) { Ahit_minr = true; Amin_r = i; } }
1299 if (!Ahit_ming) { Amin_g += accum_g[i]; if (Amin_g > At_256) { Ahit_ming = true; Amin_g = i; } }
1300 if (!Ahit_minb) { Amin_b += accum_b[i]; if (Amin_b > At_256) { Ahit_minb = true; Amin_b = i; } }
1301 // loose max
1302 if (!Ahit_maxr) { Amax_r += accum_r[max_pixel_value_analyze - i]; if (Amax_r > At_256) { Ahit_maxr = true; Amax_r = max_pixel_value_analyze - i; } }
1303 if (!Ahit_maxg) { Amax_g += accum_g[max_pixel_value_analyze - i]; if (Amax_g > At_256) { Ahit_maxg = true; Amax_g = max_pixel_value_analyze - i; } }
1304 if (!Ahit_maxb) { Amax_b += accum_b[max_pixel_value_analyze - i]; if (Amax_b > At_256) { Ahit_maxb = true; Amax_b = max_pixel_value_analyze - i; } }
1305 }
1306
1307 auto Fst_r = sqrt(st_r / pixels);
1308 auto Fst_g = sqrt(st_g / pixels);
1309 auto Fst_b = sqrt(st_b / pixels);
1310
1311 char text[512];
1312 const bool StatsAsInteger16 = false;
1313 if(StatsAsInteger16)
1314 sprintf(text,
1315 "At 16 bits. Frame: %-8u ( Red / Green / Blue )\n"
1316 " Average: ( %7.2f / %7.2f / %7.2f )\n"
1317 "Standard Deviation: ( %7.2f / %7.2f / %7.2f )\n"
1318 " Minimum: ( %7.2f / %7.2f / %7.2f )\n"
1319 " Maximum: ( %7.2f / %7.2f / %7.2f )\n"
1320 " Loose Minimum: ( %5d / %5d / %5d )\n"
1321 " Loose Maximum: ( %5d / %5d / %5d )\n"
1322 ,
1323 (unsigned int)n,
1324 avg_r * 65535, avg_g * 65535, avg_b * 65535,
1325 Fst_r * 65535, Fst_g * 65535, Fst_b * 65535,
1326 rgbplanedata.data[0].real_min * 65535, rgbplanedata.data[1].real_min * 65535, rgbplanedata.data[2].real_min * 65535,
1327 rgbplanedata.data[0].real_max * 65535, rgbplanedata.data[1].real_max * 65535, rgbplanedata.data[2].real_max * 65535,
1328 Amin_r, Amin_g, Amin_b,
1329 Amax_r, Amax_g, Amax_b
1330 );
1331 else // stats as Float
1332 sprintf(text,
1333 " Frame: %-8u ( Red / Green / Blue )\n"
1334 " Average: ( %7.5f / %7.5f / %7.5f )\n"
1335 "Standard Deviation: ( %7.5f / %7.5f / %7.5f )\n"
1336 " Minimum: ( %7.5f / %7.5f / %7.5f )\n"
1337 " Maximum: ( %7.5f / %7.5f / %7.5f )\n"
1338 " Loose Minimum: ( %7.5f / %7.5f / %7.5f )\n"
1339 " Loose Maximum: ( %7.5f / %7.5f / %7.5f )\n"
1340 ,
1341 (unsigned int)n,
1342 avg_r, avg_g, avg_b,
1343 Fst_r, Fst_g, Fst_b,
1344 rgbplanedata.data[0].real_min, rgbplanedata.data[1].real_min, rgbplanedata.data[2].real_min,
1345 rgbplanedata.data[0].real_max, rgbplanedata.data[1].real_max, rgbplanedata.data[2].real_max,
1346 Amin_r / 65535.0, Amin_g / 65535.0, Amin_b / 65535.0,
1347 Amax_r / 65535.0, Amax_g / 65535.0, Amax_b / 65535.0
1348 );
1349 env->ApplyMessage(&frame, vi, text, vi.width / 4, 0xa0a0a0, 0, 0);
1350 }
1351 else {
1352
1353
5/10
✓ Branch 151 → 152 taken 1 time.
✗ Branch 151 → 226 not taken.
✓ Branch 152 → 153 taken 1 time.
✗ Branch 152 → 155 not taken.
✓ Branch 153 → 154 taken 1 time.
✗ Branch 153 → 226 not taken.
✗ Branch 154 → 155 not taken.
✓ Branch 154 → 156 taken 1 time.
✗ Branch 157 → 158 not taken.
✓ Branch 157 → 168 taken 1 time.
1 if (vi.IsPlanarRGB() || vi.IsPlanarRGBA())
1354 {
1355 const BYTE* p_g = frame->GetReadPtr(PLANAR_G);;
1356 const BYTE* p_b = frame->GetReadPtr(PLANAR_B);
1357 const BYTE* p_r = frame->GetReadPtr(PLANAR_R);
1358 if (bits_per_pixel == 8)
1359 fill_accum_rgb_planar_c<uint8_t>(p_r, p_g, p_b, pitch, accum_r, accum_g, accum_b, w, h, max_pixel_value_analyze);
1360 else if (bits_per_pixel <= 16)
1361 fill_accum_rgb_planar_c<uint16_t>(p_r, p_g, p_b, pitch, accum_r, accum_g, accum_b, w, h, max_pixel_value_analyze);
1362 else // 32 bit float
1363 ;// handled in other branch;
1364 }
1365 else {
1366 // packed RGB
1367
1/2
✓ Branch 169 → 170 taken 1 time.
✗ Branch 169 → 226 not taken.
1 const BYTE* srcp = frame->GetReadPtr();
1368
2/8
✓ Branch 170 → 171 taken 1 time.
✗ Branch 170 → 226 not taken.
✗ Branch 171 → 172 not taken.
✓ Branch 171 → 174 taken 1 time.
✗ Branch 172 → 173 not taken.
✗ Branch 172 → 226 not taken.
✗ Branch 173 → 174 not taken.
✗ Branch 173 → 175 not taken.
1 const int pixel_step = vi.IsRGB24() || vi.IsRGB48() ? 3 : 4;
1369
1370
1/2
✓ Branch 176 → 177 taken 1 time.
✗ Branch 176 → 178 not taken.
1 if (pixelsize == 1)
1371 1 fill_accum_rgb_packed_c<uint8_t>(srcp, pitch, accum_r, accum_g, accum_b, w, h, pixel_step);
1372 else
1373 fill_accum_rgb_packed_c<uint16_t>(srcp, pitch, accum_r, accum_g, accum_b, w, h, pixel_step);
1374 }
1375
1376 1 double avg_r = 0, avg_g = 0, avg_b = 0;
1377 1 double st_r = 0, st_g = 0, st_b = 0;
1378 1 int min_r = 0, min_g = 0, min_b = 0;
1379 1 int max_r = 0, max_g = 0, max_b = 0;
1380 1 bool hit_r = false, hit_g = false, hit_b = false;
1381 1 int Amin_r = 0, Amin_g = 0, Amin_b = 0;
1382 1 int Amax_r = 0, Amax_g = 0, Amax_b = 0;
1383 1 bool Ahit_minr = false, Ahit_ming = false, Ahit_minb = false;
1384 1 bool Ahit_maxr = false, Ahit_maxg = false, Ahit_maxb = false;
1385 1 int At_256 = (pixels + 128) / 256; // When 1/256th of all pixels have been reached, trigger "Loose min/max"
1386
1387
2/2
✓ Branch 211 → 180 taken 256 times.
✓ Branch 211 → 212 taken 1 time.
257 for (int i = 0; i < analyze_lookup_size; i++) {
1388 256 avg_r += (double)accum_r[i] * i;
1389 256 avg_g += (double)accum_g[i] * i;
1390 256 avg_b += (double)accum_b[i] * i;
1391
1392
1/2
✓ Branch 180 → 181 taken 256 times.
✗ Branch 180 → 182 not taken.
256 if (accum_r[i] != 0) { max_r = i; hit_r = true; }
1393 else { if (!hit_r) min_r = i + 1; }
1394
1/2
✓ Branch 184 → 185 taken 256 times.
✗ Branch 184 → 186 not taken.
256 if (accum_g[i] != 0) { max_g = i; hit_g = true; }
1395 else { if (!hit_g) min_g = i + 1; }
1396
1/2
✓ Branch 188 → 189 taken 256 times.
✗ Branch 188 → 190 not taken.
256 if (accum_b[i] != 0) { max_b = i; hit_b = true; }
1397 else { if (!hit_b) min_b = i + 1; }
1398
1399
4/4
✓ Branch 192 → 193 taken 2 times.
✓ Branch 192 → 195 taken 254 times.
✓ Branch 193 → 194 taken 1 time.
✓ Branch 193 → 195 taken 1 time.
256 if (!Ahit_minr) { Amin_r += accum_r[i]; if (Amin_r > At_256) { Ahit_minr = true; Amin_r = i; } }
1400
4/4
✓ Branch 195 → 196 taken 2 times.
✓ Branch 195 → 198 taken 254 times.
✓ Branch 196 → 197 taken 1 time.
✓ Branch 196 → 198 taken 1 time.
256 if (!Ahit_ming) { Amin_g += accum_g[i]; if (Amin_g > At_256) { Ahit_ming = true; Amin_g = i; } }
1401
4/4
✓ Branch 198 → 199 taken 2 times.
✓ Branch 198 → 201 taken 254 times.
✓ Branch 199 → 200 taken 1 time.
✓ Branch 199 → 201 taken 1 time.
256 if (!Ahit_minb) { Amin_b += accum_b[i]; if (Amin_b > At_256) { Ahit_minb = true; Amin_b = i; } }
1402
1403
4/4
✓ Branch 201 → 202 taken 2 times.
✓ Branch 201 → 204 taken 254 times.
✓ Branch 202 → 203 taken 1 time.
✓ Branch 202 → 204 taken 1 time.
256 if (!Ahit_maxr) { Amax_r += accum_r[max_pixel_value_analyze - i]; if (Amax_r > At_256) { Ahit_maxr = true; Amax_r = max_pixel_value_analyze - i; } }
1404
4/4
✓ Branch 204 → 205 taken 2 times.
✓ Branch 204 → 207 taken 254 times.
✓ Branch 205 → 206 taken 1 time.
✓ Branch 205 → 207 taken 1 time.
256 if (!Ahit_maxg) { Amax_g += accum_g[max_pixel_value_analyze - i]; if (Amax_g > At_256) { Ahit_maxg = true; Amax_g = max_pixel_value_analyze - i; } }
1405
4/4
✓ Branch 207 → 208 taken 2 times.
✓ Branch 207 → 210 taken 254 times.
✓ Branch 208 → 209 taken 1 time.
✓ Branch 208 → 210 taken 1 time.
256 if (!Ahit_maxb) { Amax_b += accum_b[max_pixel_value_analyze - i]; if (Amax_b > At_256) { Ahit_maxb = true; Amax_b = max_pixel_value_analyze - i; } }
1406 }
1407
1408 1 float Favg_r = (float)(avg_r / pixels);
1409 1 float Favg_g = (float)(avg_g / pixels);
1410 1 float Favg_b = (float)(avg_b / pixels);
1411
1412
2/2
✓ Branch 214 → 213 taken 256 times.
✓ Branch 214 → 215 taken 1 time.
257 for (int i = 0; i < analyze_lookup_size; i++) {
1413 256 st_r += (float)accum_r[i] * (float(i - Favg_r) * (i - Favg_r));
1414 256 st_g += (float)accum_g[i] * (float(i - Favg_g) * (i - Favg_g));
1415 256 st_b += (float)accum_b[i] * (float(i - Favg_b) * (i - Favg_b));
1416 }
1417
1418 1 float Fst_r = (float)sqrt(st_r / pixels);
1419 1 float Fst_g = (float)sqrt(st_g / pixels);
1420 1 float Fst_b = (float)sqrt(st_b / pixels);
1421
1422 char text[512];
1423
1/2
✓ Branch 215 → 216 taken 1 time.
✗ Branch 215 → 217 not taken.
1 if (bits_per_pixel == 8)
1424 1 sprintf(text,
1425 " Frame: %-8u ( Red / Green / Blue )\n"
1426 " Average: ( %5.2f / %5.2f / %5.2f )\n"
1427 "Standard Deviation: ( %5.2f / %5.2f / %5.2f )\n"
1428 " Minimum: ( %3d / %3d / %3d )\n"
1429 " Maximum: ( %3d / %3d / %3d )\n"
1430 " Loose Minimum: ( %3d / %3d / %3d )\n"
1431 " Loose Maximum: ( %3d / %3d / %3d )\n"
1432 ,
1433 (unsigned int)n,
1434 Favg_r, Favg_g, Favg_b,
1435 Fst_r, Fst_g, Fst_b,
1436 min_r, min_g, min_b,
1437 max_r, max_g, max_b,
1438 Amin_r, Amin_g, Amin_b,
1439 Amax_r, Amax_g, Amax_b
1440 );
1441 else // if (bits_per_pixel <= 16)
1442 sprintf(text,
1443 " Frame: %-8u ( Red / Green / Blue )\n"
1444 " Average: ( %7.2f / %7.2f / %7.2f )\n"
1445 "Standard Deviation: ( %7.2f / %7.2f / %7.2f )\n"
1446 " Minimum: ( %5d / %5d / %5d )\n"
1447 " Maximum: ( %5d / %5d / %5d )\n"
1448 " Loose Minimum: ( %5d / %5d / %5d )\n"
1449 " Loose Maximum: ( %5d / %5d / %5d )\n"
1450 ,
1451 (unsigned int)n,
1452 Favg_r, Favg_g, Favg_b,
1453 Fst_r, Fst_g, Fst_b,
1454 min_r, min_g, min_b,
1455 max_r, max_g, max_b,
1456 Amin_r, Amin_g, Amin_b,
1457 Amax_r, Amax_g, Amax_b
1458 );
1459
1/2
✓ Branch 218 → 219 taken 1 time.
✗ Branch 218 → 226 not taken.
1 env->ApplyMessage(&frame, vi, text, vi.width / 4, 0xa0a0a0, 0, 0);
1460 }
1461
1/2
✓ Branch 220 → 221 taken 1 time.
✗ Branch 220 → 227 not taken.
1 env->Free(accum_r);
1462 }
1463 9 return frame;
1464 }
1465
1466
1467 AVSValue __cdecl RGBAdjust::Create(AVSValue args, void*, IScriptEnvironment* env)
1468 {
1469 return new RGBAdjust(args[ 0].AsClip(),
1470 args[ 1].AsDblDef(1.0), args[ 2].AsDblDef(1.0), args[ 3].AsDblDef(1.0), args[ 4].AsDblDef(1.0),
1471 args[ 5].AsDblDef(0.0), args[ 6].AsDblDef(0.0), args[ 7].AsDblDef(0.0), args[ 8].AsDblDef(0.0),
1472 args[ 9].AsDblDef(1.0), args[10].AsDblDef(1.0), args[11].AsDblDef(1.0), args[12].AsDblDef(1.0),
1473 args[13].AsBool(false), args[14].AsBool(false), args[15].AsBool(false), args[16].AsString(""), env );
1474 }
1475
1476
1477
1478 /* helper function for Tweak and MaskHS filters */
1479 131108 static bool ProcessPixel(double X, double Y, double startHue, double endHue,
1480 double maxSat, double minSat, double p, int &iSat)
1481 {
1482 // a hue analog
1483 131108 double T = atan2(X, Y) * 180.0 / PI;
1484
2/2
✓ Branch 2 → 3 taken 65546 times.
✓ Branch 2 → 4 taken 65562 times.
131108 if (T < 0.0) T += 360.0;
1485
1486 // startHue <= hue <= endHue
1487
2/2
✓ Branch 4 → 5 taken 8 times.
✓ Branch 4 → 8 taken 131100 times.
131108 if (startHue < endHue) {
1488
3/4
✓ Branch 5 → 6 taken 6 times.
✓ Branch 5 → 7 taken 2 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 11 taken 6 times.
8 if (T > endHue || T < startHue) return false;
1489 }
1490 else {
1491
4/4
✓ Branch 8 → 9 taken 114717 times.
✓ Branch 8 → 11 taken 16383 times.
✓ Branch 9 → 10 taken 98120 times.
✓ Branch 9 → 11 taken 16597 times.
131100 if (T<startHue && T>endHue) return false;
1492 }
1493
1494 32986 const double W = X*X + Y*Y;
1495
1496 // In Range, full adjust but no need to interpolate
1497
4/4
✓ Branch 11 → 12 taken 31152 times.
✓ Branch 11 → 14 taken 1834 times.
✓ Branch 12 → 13 taken 15350 times.
✓ Branch 12 → 14 taken 15802 times.
32986 if (minSat*minSat <= W && W <= maxSat*maxSat) return true;
1498
1499 // p == 0 (no interpolation) needed for MaskHS
1500
1/2
✓ Branch 14 → 15 taken 17636 times.
✗ Branch 14 → 16 not taken.
17636 if (p == 0.0) return false;
1501
1502 // Interpolation range is +/-p for p>0
1503 // 180 is not in degrees!
1504 // its sqrt(127^2 + 127^2): max overshoot for 8 bits; U and V is 0 +/- 127
1505 const double max = min(maxSat + p, 180.0);
1506 const double min = ::max(minSat - p, 0.0);
1507
1508 // Outside of [min-p, max+p] no adjustment
1509 // minSat-p <= (U^2 + V^2) <= maxSat+p
1510 if (W <= min*min || max*max <= W) return false; // don't adjust
1511
1512 // Interpolate saturation value
1513 const double holdSat = W < 180.0*180.0 ? sqrt(W) : 180.0;
1514
1515 if (holdSat < minSat) { // within p of lower range
1516 iSat += (int)((512 - iSat) * (minSat - holdSat) / p);
1517 }
1518 else { // within p of upper range
1519 iSat += (int)((512 - iSat) * (holdSat - maxSat) / p);
1520 }
1521
1522 return true;
1523 }
1524
1525 // for float
1526 static bool ProcessPixelUnscaled(double X, double Y, double startHue, double endHue,
1527 double maxSat, double minSat, double p, double &dSat)
1528 {
1529 // a hue analog
1530 double T = atan2(X, Y) * 180.0 / PI;
1531 if (T < 0.0) T += 360.0;
1532
1533 // startHue <= hue <= endHue
1534 if (startHue < endHue) {
1535 if (T > endHue || T < startHue) return false;
1536 }
1537 else {
1538 if (T<startHue && T>endHue) return false;
1539 }
1540
1541 const double W = X*X + Y*Y;
1542
1543 // In Range, full adjust but no need to interpolate
1544 if (minSat*minSat <= W && W <= maxSat*maxSat) return true;
1545
1546 // p == 0 (no interpolation) needed for MaskHS
1547 if (p == 0.0) return false;
1548
1549 // Interpolation range is +/-p for p>0
1550 const double max = min(maxSat + p, 180.0);
1551 const double min = ::max(minSat - p, 0.0);
1552
1553 // Outside of [min-p, max+p] no adjustment
1554 // minSat-p <= (U^2 + V^2) <= maxSat+p
1555 if (W <= min*min || max*max <= W) return false; // don't adjust
1556
1557 // Interpolate saturation value
1558 const double holdSat = W < 180.0*180.0 ? sqrt(W) : 180.0;
1559
1560 if (holdSat < minSat) { // within p of lower range
1561 dSat += ((1 - dSat) * (minSat - holdSat) / p);
1562 }
1563 else { // within p of upper range
1564 dSat += ((1 - dSat) * (holdSat - maxSat) / p);
1565 }
1566
1567 return true;
1568 }
1569
1570
1571 /**********************
1572 ****** Tweak *****
1573 **********************/
1574 template<typename pixel_t, bool bpp10_14, bool dither>
1575 6 void Tweak::tweak_calc_luma(BYTE *srcp, int src_pitch, float minY, float maxY, int width, int height)
1576 {
1577 6 float ditherval = 0.0f;
1578
8/16
void Tweak::tweak_calc_luma<float, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 14 → 3 taken 2 times.
✓ Branch 14 → 15 taken 1 time.
void Tweak::tweak_calc_luma<float, false, true>(unsigned char*, int, float, float, int, int):
✗ Branch 14 → 3 not taken.
✗ Branch 14 → 15 not taken.
void Tweak::tweak_calc_luma<unsigned char, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 14 → 3 taken 4 times.
✓ Branch 14 → 15 taken 2 times.
void Tweak::tweak_calc_luma<unsigned char, false, true>(unsigned char*, int, float, float, int, int):
✗ Branch 14 → 3 not taken.
✗ Branch 14 → 15 not taken.
void Tweak::tweak_calc_luma<unsigned short, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 14 → 3 taken 12 times.
✓ Branch 14 → 15 taken 2 times.
void Tweak::tweak_calc_luma<unsigned short, false, true>(unsigned char*, int, float, float, int, int):
✓ Branch 14 → 3 taken 6 times.
✓ Branch 14 → 15 taken 1 time.
void Tweak::tweak_calc_luma<unsigned short, true, false>(unsigned char*, int, float, float, int, int):
✗ Branch 10 → 3 not taken.
✗ Branch 10 → 11 not taken.
void Tweak::tweak_calc_luma<unsigned short, true, true>(unsigned char*, int, float, float, int, int):
✗ Branch 10 → 3 not taken.
✗ Branch 10 → 11 not taken.
30 for (int y = 0; y < height; ++y) {
1579 24 const int _y = (y << 4) & 0xf0;
1580
8/16
void Tweak::tweak_calc_luma<float, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 12 → 4 taken 10 times.
✓ Branch 12 → 13 taken 2 times.
void Tweak::tweak_calc_luma<float, false, true>(unsigned char*, int, float, float, int, int):
✗ Branch 12 → 4 not taken.
✗ Branch 12 → 13 not taken.
void Tweak::tweak_calc_luma<unsigned char, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 12 → 4 taken 32 times.
✓ Branch 12 → 13 taken 4 times.
void Tweak::tweak_calc_luma<unsigned char, false, true>(unsigned char*, int, float, float, int, int):
✗ Branch 12 → 4 not taken.
✗ Branch 12 → 13 not taken.
void Tweak::tweak_calc_luma<unsigned short, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 12 → 4 taken 96 times.
✓ Branch 12 → 13 taken 12 times.
void Tweak::tweak_calc_luma<unsigned short, false, true>(unsigned char*, int, float, float, int, int):
✓ Branch 12 → 4 taken 48 times.
✓ Branch 12 → 13 taken 6 times.
void Tweak::tweak_calc_luma<unsigned short, true, false>(unsigned char*, int, float, float, int, int):
✗ Branch 8 → 4 not taken.
✗ Branch 8 → 9 not taken.
void Tweak::tweak_calc_luma<unsigned short, true, true>(unsigned char*, int, float, float, int, int):
✗ Branch 8 → 4 not taken.
✗ Branch 8 → 9 not taken.
210 for (int x = 0; x < width; ++x) {
1581 if (dither)
1582 48 ditherval = (ditherMap[(x & 0x0f) | _y] * dither_strength + bias_dither_luma) / (float)scale_dither_luma; // 0x00..0xFF -> -0.7F .. + 0.7F (+/- maxrange/512)
1583 186 float y0 = reinterpret_cast<pixel_t *>(srcp)[x] - minY;
1584 if(bpp10_14)
1585 y0 = minY + (y0 + ditherval)*(float)dcont + (float)(1 << (bits_per_pixel - 8))*(float)dbright; // dbright parameter always 0..255. Scale to 0..255*4, 0.. 255*256
1586
4/12
void Tweak::tweak_calc_luma<float, false, false>(unsigned char*, int, float, float, int, int):
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 10 times.
void Tweak::tweak_calc_luma<float, false, true>(unsigned char*, int, float, float, int, int):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
void Tweak::tweak_calc_luma<unsigned char, false, false>(unsigned char*, int, float, float, int, int):
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 32 times.
void Tweak::tweak_calc_luma<unsigned char, false, true>(unsigned char*, int, float, float, int, int):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
void Tweak::tweak_calc_luma<unsigned short, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 5 → 6 taken 96 times.
✗ Branch 5 → 7 not taken.
void Tweak::tweak_calc_luma<unsigned short, false, true>(unsigned char*, int, float, float, int, int):
✓ Branch 5 → 6 taken 48 times.
✗ Branch 5 → 7 not taken.
186 else if(pixelsize == 2)
1587 144 y0 = minY + (y0 + ditherval)*(float)dcont + 256.0f*(float)dbright; // dbright parameter always 0..255. Scale to 0..255*4, 0.. 255*256
1588
2/12
void Tweak::tweak_calc_luma<float, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 7 → 8 taken 10 times.
✗ Branch 7 → 9 not taken.
void Tweak::tweak_calc_luma<float, false, true>(unsigned char*, int, float, float, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 9 not taken.
void Tweak::tweak_calc_luma<unsigned char, false, false>(unsigned char*, int, float, float, int, int):
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 32 times.
void Tweak::tweak_calc_luma<unsigned char, false, true>(unsigned char*, int, float, float, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 9 not taken.
void Tweak::tweak_calc_luma<unsigned short, false, false>(unsigned char*, int, float, float, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 9 not taken.
void Tweak::tweak_calc_luma<unsigned short, false, true>(unsigned char*, int, float, float, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 9 not taken.
42 else if(pixelsize == 4)
1589 10 y0 = minY + (y0 + ditherval)*(float)dcont + (float)dbright / 256.0f; // dbright parameter always 0..255, scale it to 0..1
1590 else // pixelsize == 1
1591 32 y0 = minY + ((y0 + ditherval)*(float)dcont + 1.0f*(float)dbright); // dbright parameter always 0..255. Scale to 0..255*4, 0.. 255*256
1592
1593 186 reinterpret_cast<pixel_t *>(srcp)[x] = (pixel_t)clamp(y0, minY, maxY);
1594 /*
1595 int y = int(((ii - range_low * scale_dither_luma)*_cont + _bright * scale_dither_luma + bias_dither_luma) / scale_dither_luma + range_low + 0.5); // 256 _cont & _bright param range
1596 // coring, dither:
1597 // int y = int(((ii - 16 * 256)*_cont + _bright * 256 - 127.5) / 256 + 16.5); // 256 _cont & _bright param range
1598 // coring, no dither:
1599 // int y = int(((ii - 16)*_cont + _bright) + 16.5); // 256 _cont & _bright param range
1600 // no coring, dither:
1601 // int y = int((ii *_cont + _bright * 256 - 127.5) / 256 + 0.5 ); // 256 _cont & _bright param range
1602 // no coring, no dither:
1603 // int y = int((ii *_cont + _bright) + 0.5 ); // 256 _cont & _bright param range
1604 */
1605 }
1606 24 srcp += src_pitch;
1607 }
1608 6 }
1609
1610 8 Tweak::Tweak(PClip _child, double _hue, double _sat, double _bright, double _cont, bool _coring,
1611 double _startHue, double _endHue, double _maxSat, double _minSat, double p,
1612 8 bool _dither, bool _realcalc, double _dither_strength, IScriptEnvironment* env)
1613 8 : GenericVideoFilter(_child), coring(_coring),
1614 8 dither(_dither), realcalc(_realcalc),
1615 8 dhue(_hue), dsat(_sat), dbright(_bright), dcont(_cont), dstartHue(_startHue), dendHue(_endHue),
1616
2/4
✓ Branch 2 → 3 taken 8 times.
✗ Branch 2 → 174 not taken.
✓ Branch 3 → 4 taken 8 times.
✗ Branch 3 → 172 not taken.
8 dmaxSat(_maxSat), dminSat(_minSat), dinterp(p), dither_strength((float)_dither_strength)
1617 {
1618
2/4
✓ Branch 5 → 6 taken 8 times.
✗ Branch 5 → 177 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 8 times.
8 if (vi.IsRGB())
1619 env->ThrowError("Tweak: YUV data only (no RGB)");
1620
1621
1/2
✓ Branch 8 → 9 taken 8 times.
✗ Branch 8 → 177 not taken.
8 pixelsize = vi.ComponentSize();
1622
1/2
✓ Branch 9 → 10 taken 8 times.
✗ Branch 9 → 177 not taken.
8 bits_per_pixel = vi.BitsPerComponent();
1623 8 max_pixel_value = (1 << bits_per_pixel) - 1;
1624 8 lut_size = 1 << bits_per_pixel;
1625
2/2
✓ Branch 10 → 11 taken 4 times.
✓ Branch 10 → 12 taken 4 times.
8 int safe_luma_lookup_size = (pixelsize == 1) ? 256 : 65536; // avoids lut overflow in case of non-standard content of a 10 bit clip
1626
1627 8 get_limits(limits, bits_per_pixel); // tv range limits
1628
1629 8 scale_dither_luma = 1;
1630 8 divisor_dither_luma = 1;
1631 8 bias_dither_luma = 0.0;
1632
1633 8 scale_dither_chroma = 1;
1634 8 divisor_dither_chroma = 1;
1635 8 bias_dither_chroma = 0.0;
1636
1637
2/2
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 16 taken 7 times.
8 if (pixelsize == 4)
1638 1 dither_strength /= 65536.0f; // same dither range as for a 16 bit clip
1639 // Set dither_strength = 4.0 for 10 bits or 256.0 for 16 bits in order to have same dither range as for 8 bits
1640 // Otherwise dithering is always +/- 0.5 at all bit-depth
1641
1642
2/2
✓ Branch 16 → 17 taken 1 time.
✓ Branch 16 → 21 taken 7 times.
8 if (dither) {
1643 // lut scale settings
1644 1 scale_dither_luma = 256; // lower 256 is dither value
1645 1 divisor_dither_luma *= 256;
1646 1 bias_dither_luma = -(256.0f * dither_strength - 1) / 2;
1647 // original bias: -127.5 or -(256.0f * dither_strength - 1) / 2;
1648 // dither strength =1 = (1 << (8-8))
1649 // dither min: int( (0*1-127.5)/256+0.5) = -0.498046875 + 0.5 = 0,001953125
1650 // dither max: int( (255*1-127.5)/256+0.5) = 0,998046875
1651
1652 // 16 bit: 32767,5
1653 // dither strength =256 = (1 << (16-8))
1654 // dither min: int( (0*256-32767,5)/256+0.5) = -127,498046875
1655 // dither max: int( (255*256-32767,5)/256+0.5) = 127,501953125
1656
1657
1658 1 scale_dither_chroma = 16; // lower 16 is dither value
1659 1 divisor_dither_chroma *= 16;
1660
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 1 time.
1 bias_dither_chroma = -(16.0f * dither_strength - (pixelsize==4 ? 1/256.0f : 1)) / 2; // -7.5
1661 }
1662
1663 // Flag to skip special processing if doing all pixels
1664 // If defaults, don't check for ranges, just do all
1665
5/8
✓ Branch 21 → 22 taken 7 times.
✓ Branch 21 → 26 taken 1 time.
✓ Branch 22 → 23 taken 7 times.
✗ Branch 22 → 26 not taken.
✓ Branch 23 → 24 taken 7 times.
✗ Branch 23 → 26 not taken.
✓ Branch 24 → 25 taken 7 times.
✗ Branch 24 → 26 not taken.
8 allPixels = (_startHue == 0.0 && _endHue == 360.0 && _maxSat == 150.0 && _minSat == 0.0);
1666
1667
3/4
✓ Branch 27 → 28 taken 8 times.
✗ Branch 27 → 177 not taken.
✓ Branch 28 → 29 taken 1 time.
✓ Branch 28 → 33 taken 7 times.
8 if (vi.NumComponents() == 1) {
1668
3/6
✓ Branch 29 → 30 taken 1 time.
✗ Branch 29 → 32 not taken.
✓ Branch 30 → 31 taken 1 time.
✗ Branch 30 → 32 not taken.
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 33 taken 1 time.
1 if (!(_hue == 0.0 && _sat == 1.0 && allPixels))
1669 env->ThrowError("Tweak: bright and cont are the only options available for greyscale.");
1670 }
1671
1672
2/4
✓ Branch 33 → 34 taken 8 times.
✗ Branch 33 → 35 not taken.
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 36 taken 8 times.
8 if (_startHue < 0.0 || _startHue >= 360.0)
1673 env->ThrowError("Tweak: startHue must be greater than or equal to 0.0 and less than 360.0");
1674
1675
2/4
✓ Branch 36 → 37 taken 8 times.
✗ Branch 36 → 38 not taken.
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 8 times.
8 if (_endHue <= 0.0 || _endHue > 360.0)
1676 env->ThrowError("Tweak: endHue must be greater than 0.0 and less than or equal to 360.0");
1677
1678
1/2
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 8 times.
8 if (_minSat >= _maxSat)
1679 env->ThrowError("Tweak: MinSat must be less than MaxSat");
1680
1681
2/4
✓ Branch 41 → 42 taken 8 times.
✗ Branch 41 → 43 not taken.
✗ Branch 42 → 43 not taken.
✓ Branch 42 → 44 taken 8 times.
8 if (_minSat < 0.0 || _minSat >= 150.0)
1682 env->ThrowError("Tweak: minSat must be greater than or equal to 0 and less than 150.");
1683
1684
2/4
✓ Branch 44 → 45 taken 8 times.
✗ Branch 44 → 46 not taken.
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 8 times.
8 if (_maxSat <= 0.0 || _maxSat > 150.0)
1685 env->ThrowError("Tweak: maxSat must be greater than 0 and less than or equal to 150.");
1686
1687
2/4
✓ Branch 47 → 48 taken 8 times.
✗ Branch 47 → 49 not taken.
✗ Branch 48 → 49 not taken.
✓ Branch 48 → 50 taken 8 times.
8 if (p>=150.0 || p<0.0)
1688 env->ThrowError("Tweak: Interp must be greater than or equal to 0 and less than 150.");
1689
1690 8 Sat = (int) (_sat * 512); // 9 bits extra precision
1691 8 Cont = (int) (_cont * 512);
1692 8 Bright = (int) _bright;
1693
1694 8 const double Hue = (_hue * PI) / 180.0;
1695 8 const double SIN = sin(Hue);
1696 8 const double COS = cos(Hue);
1697
1698 8 Sin = (int) (SIN * 4096 + 0.5);
1699 8 Cos = (int) (COS * 4096 + 0.5);
1700
1701 8 realcalc_luma = realcalc; // from parameter
1702 8 realcalc_chroma = realcalc;
1703
6/8
✓ Branch 50 → 51 taken 8 times.
✗ Branch 50 → 177 not taken.
✓ Branch 51 → 52 taken 8 times.
✗ Branch 51 → 54 not taken.
✓ Branch 52 → 53 taken 4 times.
✓ Branch 52 → 54 taken 4 times.
✓ Branch 55 → 56 taken 4 times.
✓ Branch 55 → 57 taken 4 times.
8 if (vi.IsPlanar() && (bits_per_pixel > 10))
1704 4 realcalc_chroma = true;
1705
6/8
✓ Branch 57 → 58 taken 8 times.
✗ Branch 57 → 177 not taken.
✓ Branch 58 → 59 taken 8 times.
✗ Branch 58 → 61 not taken.
✓ Branch 59 → 60 taken 1 time.
✓ Branch 59 → 61 taken 7 times.
✓ Branch 62 → 63 taken 1 time.
✓ Branch 62 → 64 taken 7 times.
8 if (vi.IsPlanar() && (bits_per_pixel == 32))
1706 1 realcalc_luma = true;
1707 // 8/10bit: chroma lut OK. 12+ bits: force no lookup tables.
1708 // 8-16bit: luma lut OK. float: force no lookup tables.
1709
1710 // fill brightness/constrast lookup tables
1711
6/8
✓ Branch 64 → 65 taken 6 times.
✓ Branch 64 → 67 taken 2 times.
✓ Branch 65 → 66 taken 6 times.
✗ Branch 65 → 177 not taken.
✗ Branch 66 → 67 not taken.
✓ Branch 66 → 68 taken 6 times.
✓ Branch 69 → 70 taken 2 times.
✓ Branch 69 → 103 taken 6 times.
8 if(!(realcalc_luma && vi.IsPlanar()))
1712 {
1713 2 size_t map_size = pixelsize * safe_luma_lookup_size * scale_dither_luma;
1714 // for 10-16 bit with dither: 2 * 65536 * 256 = 33 MByte
1715 // w/o dither: 2 * 65536 = 128 KByte
1716
1/2
✓ Branch 70 → 71 taken 2 times.
✗ Branch 70 → 177 not taken.
2 map = static_cast<uint8_t*>(env->Allocate(map_size, 8, AVS_NORMAL_ALLOC));
1717
1/2
✗ Branch 71 → 72 not taken.
✓ Branch 71 → 73 taken 2 times.
2 if (!map)
1718 env->ThrowError("Tweak: Could not reserve memory.");
1719
1/2
✓ Branch 73 → 74 taken 2 times.
✗ Branch 73 → 177 not taken.
2 env->AtExit(free_buffer, map);
1720
1721
1/4
✗ Branch 74 → 75 not taken.
✓ Branch 74 → 86 taken 2 times.
✗ Branch 75 → 76 not taken.
✗ Branch 75 → 86 not taken.
2 if(bits_per_pixel>8 && bits_per_pixel<16) // make lut table safe for 10-14 bit garbage
1722 std::fill_n((uint16_t *)map, map_size / pixelsize, max_pixel_value);
1723
1724
1/2
✗ Branch 86 → 87 not taken.
✓ Branch 86 → 88 taken 2 times.
2 int range_low = coring ? limits.tv_range_low : 0;
1725
1/2
✗ Branch 89 → 90 not taken.
✓ Branch 89 → 91 taken 2 times.
2 int range_high = coring ? limits.tv_range_hi_luma : max_pixel_value;
1726
1727 // dither_scale_luma = 1 if no dither, 256 if dither
1728 /* create luma lut for brightness and contrast */
1729
2/2
✓ Branch 102 → 93 taken 512 times.
✓ Branch 102 → 103 taken 2 times.
514 for (int i = 0; i < lut_size * scale_dither_luma; i++) {
1730 int ii;
1731
1/2
✗ Branch 93 → 94 not taken.
✓ Branch 93 → 95 taken 512 times.
512 if(dither) {
1732 ii = (i & 0xFFFFFF00) + (int)((i & 0xFF)*dither_strength);
1733 } else {
1734 512 ii = i;
1735 }
1736 // _bright param range is accepted as 0..256
1737 512 int y = (int)(((ii - range_low * scale_dither_luma)*_cont + _bright * (1 << (bits_per_pixel - 8)) * scale_dither_luma + bias_dither_luma) / scale_dither_luma + range_low + 0.5);
1738
1739 // coring, dither:
1740 // int y = int(((ii - 16 * 256)*_cont + _bright * 256 - 127.5) / 256 + 16.5); // 256 _cont & _bright param range
1741 // coring, no dither:
1742 // int y = int(((ii - 16)*_cont + _bright) + 16.5); // 256 _cont & _bright param range
1743 // no coring, dither:
1744 // int y = int((ii *_cont + _bright * 256 - 127.5) / 256 + 0.5 ); // 256 _cont & _bright param range
1745 // no coring, no dither:
1746 // int y = int((ii *_cont + _bright) + 0.5 ); // 256 _cont & _bright param range
1747
1/2
✓ Branch 96 → 97 taken 512 times.
✗ Branch 96 → 99 not taken.
512 if(pixelsize==1)
1748 512 map[i] = (BYTE)clamp(y, range_low, range_high);
1749 else
1750 reinterpret_cast<uint16_t *>(map)[i] = (uint16_t)clamp(y, range_low, range_high);
1751 }
1752 }
1753 // 100% equals sat=119 (= maximal saturation of valid RGB (R=255,G=B=0)
1754 // 150% (=180) - 100% (=119) overshoot
1755 8 const double minSat = 1.19 * _minSat;
1756 8 const double maxSat = 1.19 * _maxSat;
1757
1758 8 p *= 1.19; // Same units as minSat/maxSat
1759
1760
6/8
✓ Branch 103 → 104 taken 6 times.
✓ Branch 103 → 106 taken 2 times.
✓ Branch 104 → 105 taken 6 times.
✗ Branch 104 → 177 not taken.
✗ Branch 105 → 106 not taken.
✓ Branch 105 → 107 taken 6 times.
✓ Branch 108 → 109 taken 2 times.
✓ Branch 108 → 171 taken 6 times.
8 if (!(realcalc_chroma && vi.IsPlanar()))
1761 { // fill lookup tables for UV
1762 2 size_t map_size = pixelsize * lut_size * lut_size * 2 * scale_dither_chroma;
1763 // for 10 bit with dither: 2 * 1024 * 1024 * 2 * 4 = 4*64 MByte = 256M huh!
1764 // for 10 bit w/o dither: 2 * 1024 * 1024 * 2 = 64 MByte
1765
1766
1/2
✓ Branch 109 → 110 taken 2 times.
✗ Branch 109 → 177 not taken.
2 mapUV = static_cast<uint16_t*>(env->Allocate(map_size, 8, AVS_NORMAL_ALLOC)); // uint16_t for (U+V bytes), casted to uint32_t for (U+V words in non-8 bit)
1767
1/2
✗ Branch 110 → 111 not taken.
✓ Branch 110 → 112 taken 2 times.
2 if (!mapUV)
1768 env->ThrowError("Tweak: Could not reserve memory.");
1769
1/2
✓ Branch 112 → 113 taken 2 times.
✗ Branch 112 → 177 not taken.
2 env->AtExit(free_buffer, mapUV);
1770
1771
1/2
✗ Branch 113 → 114 not taken.
✓ Branch 113 → 115 taken 2 times.
2 int range_low = coring ? limits.tv_range_low : 0;
1772
1/2
✗ Branch 116 → 117 not taken.
✓ Branch 116 → 118 taken 2 times.
2 int range_high = coring ? limits.tv_range_hi_chroma : max_pixel_value;
1773
1774 2 double uv_range_corr = 1.0 / (1 << (bits_per_pixel - 8));
1775
1776
1/2
✗ Branch 119 → 120 not taken.
✓ Branch 119 → 147 taken 2 times.
2 if (dither) {
1777 // lut chroma, dither
1778 for (int d = 0; d < scale_dither_chroma; d++) { // scale = 4 0..15 mini-dither
1779 for (int u = 0; u < lut_size; u++) {
1780 // dither_strength: optional correction for 8+ bit to have the same dither range as in 8 bits
1781 const double destu = (((u << 4) + d*dither_strength) + bias_dither_chroma) / scale_dither_chroma - limits.middle_chroma; // scale_dither_chroma: 16
1782 for (int v = 0; v < lut_size; v++) {
1783 const double destv = (((v << 4) + d*dither_strength) + bias_dither_chroma) / scale_dither_chroma - limits.middle_chroma;
1784 int iSat = Sat;
1785 if (allPixels || ProcessPixel(destv * uv_range_corr, destu * uv_range_corr, _startHue, _endHue, maxSat, minSat, p, iSat)) {
1786 int du = (int)((destu*COS + destv*SIN) * iSat + 0x100) >> 9; // back from the extra 9 bits Sat precision
1787 int dv = (int)((destv*COS - destu*SIN) * iSat + 0x100) >> 9;
1788 du = clamp(du + limits.middle_chroma, range_low, range_high);
1789 dv = clamp(dv + limits.middle_chroma, range_low, range_high);
1790 if(pixelsize==1)
1791 mapUV[(u << 12) | (v << 4) | d] = (uint16_t)(du | (dv << 8)); // U and V: two bytes
1792 else
1793 reinterpret_cast<uint32_t *>(mapUV)[(u << (4+bits_per_pixel)) | (v << 4) | d] = (uint32_t)(du | (dv << 16)); // U and V: two words
1794 }
1795 else {
1796 if(pixelsize==1)
1797 mapUV[(u << 12) | (v << 4) | d] = (uint16_t)(clamp(u, range_low, range_high) | (clamp(v, range_low, range_high) << 8)); // U and V: two bytes
1798 else
1799 reinterpret_cast<uint32_t *>(mapUV)[(u << (4+bits_per_pixel)) | (v << 4) | d] = (uint32_t)(clamp(u, range_low, range_high) | ((clamp(v, range_low, range_high) << 16))); // U and V: two words
1800 }
1801 }
1802 }
1803 }
1804 }
1805 else {
1806 // lut chroma, no dither
1807
2/2
✓ Branch 170 → 148 taken 512 times.
✓ Branch 170 → 171 taken 2 times.
514 for (int u = 0; u < lut_size; u++) {
1808 512 const double destu = u - limits.middle_chroma;
1809
2/2
✓ Branch 168 → 149 taken 131072 times.
✓ Branch 168 → 169 taken 512 times.
131584 for (int v = 0; v < lut_size; v++) {
1810 131072 const double destv = v - limits.middle_chroma;
1811 131072 int iSat = Sat;
1812
7/8
✓ Branch 149 → 150 taken 65536 times.
✓ Branch 149 → 152 taken 65536 times.
✓ Branch 150 → 151 taken 65536 times.
✗ Branch 150 → 176 not taken.
✓ Branch 151 → 152 taken 6434 times.
✓ Branch 151 → 153 taken 59102 times.
✓ Branch 154 → 155 taken 71970 times.
✓ Branch 154 → 160 taken 59102 times.
131072 if (allPixels || ProcessPixel(destv * uv_range_corr, destu * uv_range_corr, _startHue, _endHue, maxSat, minSat, p, iSat)) {
1813 71970 int du = int((destu*COS + destv*SIN) * iSat) >> 9; // back from the extra 9 bits Sat precision
1814 71970 int dv = int((destv*COS - destu*SIN) * iSat) >> 9;
1815 71970 du = clamp(du + limits.middle_chroma, range_low, range_high);
1816 71970 dv = clamp(dv + limits.middle_chroma, range_low, range_high);
1817
1/2
✓ Branch 157 → 158 taken 71970 times.
✗ Branch 157 → 159 not taken.
71970 if(pixelsize==1)
1818 71970 mapUV[(u << 8) | v] = (uint16_t)(du | (dv << 8)); // U and V: two bytes
1819 else
1820 reinterpret_cast<uint32_t *>(mapUV)[(u << bits_per_pixel) | v] = (uint32_t)(du | (dv << 16)); // U and V: two words
1821 }
1822 else {
1823
1/2
✓ Branch 160 → 161 taken 59102 times.
✗ Branch 160 → 164 not taken.
59102 if(pixelsize==1)
1824 59102 mapUV[(u << 8) | v] = (uint16_t)(clamp(u, range_low, range_high) | (clamp(v, range_low, range_high) << 8)); // U and V: two bytes
1825 else
1826 reinterpret_cast<uint32_t *>(mapUV)[(u << bits_per_pixel) | v] = (uint32_t)(clamp(u, range_low, range_high) | (clamp(v, range_low, range_high) << 16)); // U and V: two words
1827 }
1828 }
1829 }
1830 }
1831 }
1832 8 }
1833
1834
1835 template<typename pixel_t, bool dither>
1836 6 void Tweak::tweak_calc_chroma(BYTE *srcpu, BYTE *srcpv, int src_pitch, int width, int height, float minUV, float maxUV)
1837 {
1838 // no lookup, alway true for 16/32 bit, optional for 8 bit
1839 6 const double Hue = (dhue * PI) / 180.0;
1840 // 100% equals sat=119 (= maximal saturation of valid RGB (R=255,G=B=0)
1841 // 150% (=180) - 100% (=119) overshoot
1842 6 const double minSat = 1.19 * dminSat;
1843 6 const double maxSat = 1.19 * dmaxSat;
1844
1845 6 const double p = dinterp * 1.19; // Same units as minSat/maxSat
1846
1847 6 const int minUVi = (int)minUV;
1848 6 const int maxUVi = (int)maxUV;
1849
1850 6 float ditherval = 0.0;
1851 float u, v;
1852 6 const float cosHue = (float)cos(Hue);
1853 6 const float sinHue = (float)sin(Hue);
1854 // no lut, realcalc, float internals
1855 6 const float pixel_range = sizeof(pixel_t) == 4 ? 1.0f : (float)(max_pixel_value + 1);
1856
1857 6 double uv_range_corr = 255.0;
1858
1859 6 const bool isFloat = sizeof(pixel_t) == 4;
1860
1861
8/12
void Tweak::tweak_calc_chroma<float, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 21 → 3 taken 2 times.
✓ Branch 21 → 22 taken 1 time.
void Tweak::tweak_calc_chroma<float, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 21 → 3 not taken.
✗ Branch 21 → 22 not taken.
void Tweak::tweak_calc_chroma<unsigned char, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 21 → 3 taken 2 times.
✓ Branch 21 → 22 taken 2 times.
void Tweak::tweak_calc_chroma<unsigned char, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 21 → 3 not taken.
✗ Branch 21 → 22 not taken.
void Tweak::tweak_calc_chroma<unsigned short, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 21 → 3 taken 6 times.
✓ Branch 21 → 22 taken 2 times.
void Tweak::tweak_calc_chroma<unsigned short, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 21 → 3 taken 3 times.
✓ Branch 21 → 22 taken 1 time.
19 for (int y = 0; y < height; ++y) {
1862 13 const int _y = (y << 2) & 0xC;
1863
8/12
void Tweak::tweak_calc_chroma<float, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 19 → 4 taken 10 times.
✓ Branch 19 → 20 taken 2 times.
void Tweak::tweak_calc_chroma<float, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 19 → 4 not taken.
✗ Branch 19 → 20 not taken.
void Tweak::tweak_calc_chroma<unsigned char, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 19 → 4 taken 16 times.
✓ Branch 19 → 20 taken 2 times.
void Tweak::tweak_calc_chroma<unsigned char, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 19 → 4 not taken.
✗ Branch 19 → 20 not taken.
void Tweak::tweak_calc_chroma<unsigned short, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 19 → 4 taken 24 times.
✓ Branch 19 → 20 taken 6 times.
void Tweak::tweak_calc_chroma<unsigned short, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 19 → 4 taken 12 times.
✓ Branch 19 → 20 taken 3 times.
75 for (int x = 0; x < width; ++x) {
1864 if (dither)
1865 12 ditherval = ((float(ditherMap4[(x & 0x3) | _y]) * dither_strength + bias_dither_chroma) / scale_dither_chroma); // +/-0.5 on 0..255 range
1866 62 pixel_t orig_u = reinterpret_cast<pixel_t *>(srcpu)[x];
1867 62 pixel_t orig_v = reinterpret_cast<pixel_t *>(srcpv)[x] ;
1868 62 u = isFloat ? (orig_u - limits.middle_chroma_f) : (orig_u - limits.middle_chroma);
1869 62 v = isFloat ? (orig_v - limits.middle_chroma_f) : (orig_v - limits.middle_chroma);
1870
1871 62 u = (u + (dither ? ditherval : 0)) / (sizeof(pixel_t) == 4 ? 1.0f : pixel_range); // going from 0..1 to +/-0.5
1872 62 v = (v + (dither ? ditherval : 0)) / (sizeof(pixel_t) == 4 ? 1.0f : pixel_range);
1873
1874 62 double dWorkSat = dsat; // init from original param
1875
8/48
void Tweak::tweak_calc_chroma<float, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 10 times.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 23 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✓ Branch 9 → 10 taken 10 times.
✗ Branch 9 → 15 not taken.
void Tweak::tweak_calc_chroma<float, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 7 not taken.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 23 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 15 not taken.
void Tweak::tweak_calc_chroma<unsigned char, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 16 times.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 23 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✓ Branch 9 → 10 taken 16 times.
✗ Branch 9 → 15 not taken.
void Tweak::tweak_calc_chroma<unsigned char, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 7 not taken.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 23 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 15 not taken.
void Tweak::tweak_calc_chroma<unsigned short, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 24 times.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 23 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✓ Branch 9 → 10 taken 24 times.
✗ Branch 9 → 15 not taken.
void Tweak::tweak_calc_chroma<unsigned short, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 12 times.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 23 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✓ Branch 9 → 10 taken 12 times.
✗ Branch 9 → 15 not taken.
62 if(allPixels || ProcessPixelUnscaled(v * uv_range_corr, u * uv_range_corr, dstartHue, dendHue, maxSat, minSat, p, dWorkSat))
1876 {
1877 62 float du = ((u*cosHue + v*sinHue) * (float)dWorkSat);
1878 62 float dv = ((v*cosHue - u*sinHue) * (float)dWorkSat);
1879
1880 if (isFloat) {
1881 10 du = du + limits.middle_chroma_f;
1882 10 dv = dv + limits.middle_chroma_f;
1883 }
1884 else {
1885 // back to 0..1
1886 52 du = du + 0.5f;
1887 52 dv = dv + 0.5f;
1888 }
1889
1890 if(isFloat) {
1891 10 reinterpret_cast<pixel_t *>(srcpu)[x] = (pixel_t)clamp(du, minUV, maxUV);
1892 10 reinterpret_cast<pixel_t *>(srcpv)[x] = (pixel_t)clamp(dv, minUV, maxUV);
1893 } else {
1894 52 reinterpret_cast<pixel_t *>(srcpu)[x] = (pixel_t)clamp((int)(du * pixel_range), minUVi, maxUVi);
1895 52 reinterpret_cast<pixel_t *>(srcpv)[x] = (pixel_t)clamp((int)(dv * pixel_range), minUVi, maxUVi);
1896 }
1897 }
1898 else {
1899 if(isFloat) {
1900 reinterpret_cast<pixel_t *>(srcpu)[x] = (pixel_t)clamp((float)orig_u, minUV, maxUV);
1901 reinterpret_cast<pixel_t *>(srcpv)[x] = (pixel_t)clamp((float)orig_v, minUV, maxUV);
1902 } else {
1903 reinterpret_cast<pixel_t *>(srcpu)[x] = (pixel_t)clamp((int)(orig_u), minUVi, maxUVi);
1904 reinterpret_cast<pixel_t *>(srcpv)[x] = (pixel_t)clamp((int)(orig_v), minUVi, maxUVi);
1905 }
1906 }
1907 }
1908 13 srcpu += src_pitch;
1909 13 srcpv += src_pitch;
1910 }
1911
1912 6 }
1913
1914
1915 8 PVideoFrame __stdcall Tweak::GetFrame(int n, IScriptEnvironment* env)
1916 {
1917 8 PVideoFrame src = child->GetFrame(n, env);
1918
1/2
✓ Branch 4 → 5 taken 8 times.
✗ Branch 4 → 155 not taken.
8 env->MakeWritable(&src);
1919
1920
1/2
✓ Branch 6 → 7 taken 8 times.
✗ Branch 6 → 155 not taken.
8 BYTE* srcp = src->GetWritePtr();
1921
1922
1/2
✓ Branch 8 → 9 taken 8 times.
✗ Branch 8 → 155 not taken.
8 int src_pitch = src->GetPitch();
1923
1/2
✓ Branch 10 → 11 taken 8 times.
✗ Branch 10 → 155 not taken.
8 int height = src->GetHeight();
1924
1/2
✓ Branch 12 → 13 taken 8 times.
✗ Branch 12 → 155 not taken.
8 int row_size = src->GetRowSize();
1925
1926
2/4
✓ Branch 13 → 14 taken 8 times.
✗ Branch 13 → 155 not taken.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 31 taken 8 times.
8 if (vi.IsYUY2()) {
1927
1928 if (dither) {
1929 const int UVwidth = vi.width / 2;
1930 for (int y = 0; y < height; y++) {
1931 {const int _y = (y << 4) & 0xf0;
1932 for (int x = 0; x < vi.width; ++x) {
1933 /* brightness and contrast */
1934 srcp[x * 2] = map[srcp[x * 2] << 8 | ditherMap[(x & 0x0f) | _y]];
1935 }}
1936 {const int _y = (y << 2) & 0xC;
1937 for (int x = 0; x < UVwidth; ++x) {
1938 const int _dither = ditherMap4[(x & 0x3) | _y];
1939 /* hue and saturation */
1940 const int u = srcp[x * 4 + 1];
1941 const int v = srcp[x * 4 + 3];
1942 const int mapped = mapUV[(u << 12) | (v << 4) | _dither];
1943 srcp[x * 4 + 1] = (BYTE)(mapped & 0xff);
1944 srcp[x * 4 + 3] = (BYTE)(mapped >> 8);
1945 }}
1946 srcp += src_pitch;
1947 }
1948 }
1949 else {
1950 for (int y = 0; y < height; y++)
1951 {
1952 for (int x = 0; x < row_size; x += 4)
1953 {
1954 /* brightness and contrast */
1955 srcp[x] = map[srcp[x]];
1956 srcp[x + 2] = map[srcp[x + 2]];
1957
1958 /* hue and saturation */
1959 const int u = srcp[x + 1];
1960 const int v = srcp[x + 3];
1961 const int mapped = mapUV[(u << 8) | v];
1962 srcp[x + 1] = (BYTE)(mapped & 0xff);
1963 srcp[x + 3] = (BYTE)(mapped >> 8);
1964 }
1965 srcp += src_pitch;
1966 }
1967 }
1968 // YUY2 end
1969 }
1970
2/4
✓ Branch 31 → 32 taken 8 times.
✗ Branch 31 → 155 not taken.
✓ Branch 32 → 33 taken 8 times.
✗ Branch 32 → 153 not taken.
8 else if (vi.IsPlanar()) {
1971 // brightness and contrast
1972 // no_lut and lut
1973 8 int width = row_size / pixelsize;
1974
2/2
✓ Branch 33 → 34 taken 6 times.
✓ Branch 33 → 61 taken 2 times.
8 if (realcalc_luma)
1975 {
1976 // no luma lookup! alway true for 32 bit, optional for 8-16 bits
1977 float maxY;
1978 float minY;
1979 // unique for each bit-depth, difference in the innermost loop (speed)
1980
1/2
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 36 taken 6 times.
6 maxY = (float)(coring ? limits.tv_range_hi_luma : max_pixel_value);
1981
1/2
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 6 times.
6 minY = (float)(coring ? limits.tv_range_low : 0);
1982
1983
2/2
✓ Branch 40 → 41 taken 2 times.
✓ Branch 40 → 44 taken 4 times.
6 if(pixelsize == 1) {
1984
1/2
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 43 taken 2 times.
2 if(dither)
1985 tweak_calc_luma<uint8_t, false, true>(srcp, src_pitch, minY, maxY, width, height);
1986 else
1987 2 tweak_calc_luma<uint8_t, false, false>(srcp, src_pitch, minY, maxY, width, height);
1988
1/2
✗ Branch 44 → 45 not taken.
✓ Branch 44 → 48 taken 4 times.
4 } else if (bits_per_pixel < 16) {
1989 if(dither)
1990 tweak_calc_luma<uint16_t, true, true>(srcp, src_pitch, minY, maxY, width, height);
1991 else
1992 tweak_calc_luma<uint16_t, true, false>(srcp, src_pitch, minY, maxY, width, height);
1993
2/2
✓ Branch 48 → 49 taken 3 times.
✓ Branch 48 → 52 taken 1 time.
4 } else if(bits_per_pixel == 16) {
1994
2/2
✓ Branch 49 → 50 taken 1 time.
✓ Branch 49 → 51 taken 2 times.
3 if(dither)
1995 1 tweak_calc_luma<uint16_t, false, true>(srcp, src_pitch, minY, maxY, width, height);
1996 else
1997 2 tweak_calc_luma<uint16_t, false, false>(srcp, src_pitch, minY, maxY, width, height);
1998 } else { // float
1999
1/2
✗ Branch 52 → 53 not taken.
✓ Branch 52 → 54 taken 1 time.
1 maxY = coring ? 235.0f / 256 : 1.0f; // scale into 0..1 range
2000
1/2
✗ Branch 55 → 56 not taken.
✓ Branch 55 → 57 taken 1 time.
1 minY = coring ? 16.0f / 256 : 0;
2001
1/2
✗ Branch 58 → 59 not taken.
✓ Branch 58 → 60 taken 1 time.
1 if(dither)
2002 tweak_calc_luma<float, false, true>(srcp, src_pitch, minY, maxY, width, height);
2003 else
2004 1 tweak_calc_luma<float, false, false>(srcp, src_pitch, minY, maxY, width, height);
2005 }
2006 }
2007 else {
2008 /* brightness and contrast */
2009 // use luma lookup for 8-16 bits
2010
1/2
✗ Branch 61 → 62 not taken.
✓ Branch 61 → 75 taken 2 times.
2 if (dither) {
2011 if(pixelsize==1) {
2012 for (int y = 0; y < height; ++y) {
2013 const int _y = (y << 4) & 0xf0;
2014 for (int x = 0; x < width; ++x) {
2015 /* brightness and contrast */
2016 srcp[x] = map[srcp[x] << 8 | ditherMap[(x & 0x0f) | _y]];
2017 }
2018 srcp += src_pitch;
2019 }
2020 }
2021 else { // pixelsize == 2
2022 for (int y = 0; y < height; ++y) {
2023 const int _y = (y << 4) & 0xf0;
2024 for (int x = 0; x < width; ++x) {
2025 reinterpret_cast<uint16_t *>(srcp)[x] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(srcp)[x] << 8 | ditherMap[(x & 0x0f) | _y]];
2026 // no clamp, map is safely sized
2027 }
2028 srcp += src_pitch;
2029 }
2030 }
2031 }
2032 else {
2033
1/2
✓ Branch 75 → 76 taken 2 times.
✗ Branch 75 → 82 not taken.
2 if(pixelsize==1) {
2034
2/2
✓ Branch 81 → 77 taken 5 times.
✓ Branch 81 → 88 taken 2 times.
7 for (int y = 0; y < height; ++y) {
2035
2/2
✓ Branch 79 → 78 taken 37 times.
✓ Branch 79 → 80 taken 5 times.
42 for (int x = 0; x < width; ++x) {
2036 37 srcp[x] = map[srcp[x]];
2037 }
2038 5 srcp += src_pitch;
2039 }
2040 }
2041 else { // pixelsize == 2
2042 for (int y = 0; y < height; ++y) {
2043 for (int x = 0; x < width; ++x) {
2044 reinterpret_cast<uint16_t *>(srcp)[x] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(srcp)[x]];
2045 // no clamp, map is safely sized
2046 }
2047 srcp += src_pitch;
2048 }
2049 }
2050 }
2051 }
2052 // Y: brightness and contrast done
2053
2054 // UV: hue and saturation start
2055
1/2
✓ Branch 89 → 90 taken 8 times.
✗ Branch 89 → 155 not taken.
8 src_pitch = src->GetPitch(PLANAR_U);
2056
1/2
✓ Branch 91 → 92 taken 8 times.
✗ Branch 91 → 155 not taken.
8 BYTE * srcpu = src->GetWritePtr(PLANAR_U);
2057
1/2
✓ Branch 93 → 94 taken 8 times.
✗ Branch 93 → 155 not taken.
8 BYTE * srcpv = src->GetWritePtr(PLANAR_V);
2058
1/2
✓ Branch 95 → 96 taken 8 times.
✗ Branch 95 → 155 not taken.
8 row_size = src->GetRowSize(PLANAR_U);
2059
1/2
✓ Branch 97 → 98 taken 8 times.
✗ Branch 97 → 155 not taken.
8 height = src->GetHeight(PLANAR_U);
2060 8 width = row_size / pixelsize;
2061
2062
2/2
✓ Branch 98 → 99 taken 6 times.
✓ Branch 98 → 122 taken 2 times.
8 if (realcalc_chroma) {
2063 // no lookup, alway true for > 10 bit, optional for 8/10 bit
2064
1/2
✗ Branch 99 → 100 not taken.
✓ Branch 99 → 101 taken 6 times.
6 float maxUV = (float)(coring ? limits.tv_range_hi_chroma : max_pixel_value);
2065
1/2
✗ Branch 102 → 103 not taken.
✓ Branch 102 → 104 taken 6 times.
6 float minUV = (float)(coring ? limits.tv_range_low : 0);
2066
2/2
✓ Branch 105 → 106 taken 2 times.
✓ Branch 105 → 109 taken 4 times.
6 if(pixelsize == 1) {
2067
1/2
✗ Branch 106 → 107 not taken.
✓ Branch 106 → 108 taken 2 times.
2 if (dither)
2068 tweak_calc_chroma<uint8_t, true>(srcpu, srcpv, src_pitch, width, height, minUV, maxUV);
2069 else
2070
1/2
✓ Branch 108 → 153 taken 2 times.
✗ Branch 108 → 155 not taken.
2 tweak_calc_chroma<uint8_t, false>(srcpu, srcpv, src_pitch, width, height, minUV, maxUV);
2071
2/2
✓ Branch 109 → 110 taken 3 times.
✓ Branch 109 → 113 taken 1 time.
4 } else if(pixelsize==2) {
2072
2/2
✓ Branch 110 → 111 taken 1 time.
✓ Branch 110 → 112 taken 2 times.
3 if (dither)
2073
1/2
✓ Branch 111 → 153 taken 1 time.
✗ Branch 111 → 155 not taken.
1 tweak_calc_chroma<uint16_t, true>(srcpu, srcpv, src_pitch, width, height, minUV, maxUV);
2074 else
2075
1/2
✓ Branch 112 → 153 taken 2 times.
✗ Branch 112 → 155 not taken.
2 tweak_calc_chroma<uint16_t, false>(srcpu, srcpv, src_pitch, width, height, minUV, maxUV);
2076 } else { // pixelsize == 4
2077
1/2
✗ Branch 113 → 114 not taken.
✓ Branch 113 → 115 taken 1 time.
1 maxUV = coring ? limits.tv_range_hi_chroma_f : limits.full_range_hi_chroma_f;
2078
1/2
✗ Branch 116 → 117 not taken.
✓ Branch 116 → 118 taken 1 time.
1 minUV = coring ? limits.tv_range_low_chroma_f : limits.full_range_low_chroma_f;
2079
1/2
✗ Branch 119 → 120 not taken.
✓ Branch 119 → 121 taken 1 time.
1 if (dither)
2080 tweak_calc_chroma<float, true>(srcpu, srcpv, src_pitch, width, height, minUV, maxUV);
2081 else
2082
1/2
✓ Branch 121 → 153 taken 1 time.
✗ Branch 121 → 155 not taken.
1 tweak_calc_chroma<float, false>(srcpu, srcpv, src_pitch, width, height, minUV, maxUV);
2083 }
2084 }
2085 else { // lookup UV
2086
1/2
✗ Branch 122 → 123 not taken.
✓ Branch 122 → 138 taken 2 times.
2 if (dither) {
2087 // lut + dither
2088 if(pixelsize==1) {
2089 for (int y = 0; y < height; ++y) {
2090 const int _y = (y << 2) & 0xC;
2091 for (int x = 0; x < width; ++x) {
2092 const int _dither = ditherMap4[(x & 0x3) | _y];
2093 /* hue and saturation */
2094 const int u = srcpu[x];
2095 const int v = srcpv[x];
2096 const int mapped = mapUV[(u << 12) | (v << 4) | _dither];
2097 srcpu[x] = (BYTE)(mapped & 0xff);
2098 srcpv[x] = (BYTE)(mapped >> 8);
2099 }
2100 srcpu += src_pitch;
2101 srcpv += src_pitch;
2102 }
2103 }
2104 else { // pixelsize == 2
2105 for (int y = 0; y < height; ++y) {
2106 const int _y = (y << 2) & 0xC;
2107 for (int x = 0; x < width; ++x) {
2108 const int _dither = ditherMap4[(x & 0x3) | _y]; // 0..15
2109 /* hue and saturation */
2110 const int u = clamp(0,(int)reinterpret_cast<uint16_t *>(srcpu)[x], max_pixel_value);
2111 const int v = clamp(0,(int)reinterpret_cast<uint16_t *>(srcpv)[x], max_pixel_value);
2112 const unsigned int mapped = reinterpret_cast<uint32_t *>(mapUV)[(u << (4+bits_per_pixel)) | (v << 4) | _dither];
2113 reinterpret_cast<uint16_t *>(srcpu)[x] = (uint16_t)(mapped & 0xffff);
2114 reinterpret_cast<uint16_t *>(srcpv)[x] = (uint16_t)(mapped >> 16);
2115 }
2116 srcpu += src_pitch;
2117 srcpv += src_pitch;
2118 }
2119 }
2120 }
2121 else {
2122 // lut + no dither
2123
1/2
✓ Branch 138 → 139 taken 2 times.
✗ Branch 138 → 145 not taken.
2 if(pixelsize==1) {
2124
2/2
✓ Branch 144 → 140 taken 5 times.
✓ Branch 144 → 153 taken 2 times.
7 for (int y = 0; y < height; ++y) {
2125
2/2
✓ Branch 142 → 141 taken 37 times.
✓ Branch 142 → 143 taken 5 times.
42 for (int x = 0; x < width; ++x) {
2126 /* hue and saturation */
2127 37 const int u = srcpu[x];
2128 37 const int v = srcpv[x];
2129 37 const int mapped = mapUV[(u << 8) | v];
2130 37 srcpu[x] = (BYTE)(mapped & 0xff);
2131 37 srcpv[x] = (BYTE)(mapped >> 8);
2132 }
2133 5 srcpu += src_pitch;
2134 5 srcpv += src_pitch;
2135 }
2136 }
2137 else { // pixelsize == 2
2138 for (int y = 0; y < height; ++y) {
2139 for (int x = 0; x < width; ++x) {
2140 const int u = clamp(0,(int)reinterpret_cast<uint16_t *>(srcpu)[x], max_pixel_value);
2141 const int v = clamp(0,(int)reinterpret_cast<uint16_t *>(srcpv)[x], max_pixel_value);
2142 const unsigned int mapped = reinterpret_cast<uint32_t *>(mapUV)[(u << bits_per_pixel) | v];
2143 reinterpret_cast<uint16_t *>(srcpu)[x] = (uint16_t)(mapped & 0xffff);
2144 reinterpret_cast<uint16_t *>(srcpv)[x] = (uint16_t)(mapped >> 16);
2145 }
2146 srcpu += src_pitch;
2147 srcpv += src_pitch;
2148 }
2149 }
2150 }
2151 }
2152 }
2153
2154 8 return src;
2155 }
2156
2157 AVSValue __cdecl Tweak::Create(AVSValue args, void* , IScriptEnvironment* env)
2158 {
2159 return new Tweak(args[0].AsClip(),
2160 args[1].AsDblDef(0.0), // hue
2161 args[2].AsDblDef(1.0), // sat
2162 args[3].AsDblDef(0.0), // bright
2163 args[4].AsDblDef(1.0), // cont
2164 args[5].AsBool(true), // coring
2165 // not used even on intel. // args[6].AsBool(false), // sse
2166 args[7].AsDblDef(0.0), // startHue
2167 args[8].AsDblDef(360.0), // endHue
2168 args[9].AsDblDef(150.0), // maxSat
2169 args[10].AsDblDef(0.0), // minSat
2170 args[11].AsDblDef(16.0 / 1.19),// interp
2171 args[12].AsBool(false), // dither
2172 args[13].AsBool(false), // realcalc: force no-lookup (pure float calculation pixel)
2173 args[14].AsDblDef(1.0), // dither_strength 1.0 = +/-0.5 on the 0.255 range, scaled for others
2174 env);
2175 }
2176
2177 /**********************
2178 ****** MaskHS *****
2179 **********************/
2180
2181 11 MaskHS::MaskHS(PClip _child, double _startHue, double _endHue, double _maxSat, double _minSat, bool _coring, bool _realcalc,
2182 11 IScriptEnvironment* env)
2183
2/4
✓ Branch 2 → 3 taken 11 times.
✗ Branch 2 → 87 not taken.
✓ Branch 3 → 4 taken 11 times.
✗ Branch 3 → 85 not taken.
11 : GenericVideoFilter(_child), dstartHue(_startHue), dendHue(_endHue), dmaxSat(_maxSat), dminSat(_minSat), coring(_coring), realcalc(_realcalc)
2184 {
2185
2/4
✓ Branch 5 → 6 taken 11 times.
✗ Branch 5 → 89 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 11 times.
11 if (vi.IsRGB())
2186 env->ThrowError("MaskHS: YUV data only (no RGB)");
2187
2188
2/4
✓ Branch 8 → 9 taken 11 times.
✗ Branch 8 → 89 not taken.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 11 times.
11 if (vi.NumComponents() == 1) {
2189 env->ThrowError("MaskHS: clip must contain chroma.");
2190 }
2191
2192
4/4
✓ Branch 11 → 12 taken 10 times.
✓ Branch 11 → 13 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 14 taken 9 times.
11 if (dstartHue < 0.0 || dstartHue >= 360.0)
2193
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 89 taken 2 times.
2 env->ThrowError("MaskHS: startHue must be greater than or equal to 0.0 and less than 360.0");
2194
2195
4/4
✓ Branch 14 → 15 taken 8 times.
✓ Branch 14 → 16 taken 1 time.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 17 taken 7 times.
9 if (dendHue <= 0.0 || dendHue > 360.0)
2196
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 89 taken 2 times.
2 env->ThrowError("MaskHS: endHue must be greater than 0.0 and less than or equal to 360.0");
2197
2198
2/2
✓ Branch 17 → 18 taken 2 times.
✓ Branch 17 → 19 taken 5 times.
7 if (dminSat >= dmaxSat)
2199
1/2
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 89 taken 2 times.
2 env->ThrowError("MaskHS: MinSat must be less than MaxSat");
2200
2201
3/4
✓ Branch 19 → 20 taken 4 times.
✓ Branch 19 → 21 taken 1 time.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 4 times.
5 if (dminSat < 0.0 || dminSat >= 150.0)
2202
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 89 taken 1 time.
1 env->ThrowError("MaskHS: minSat must be greater than or equal to 0 and less than 150.");
2203
2204
3/4
✓ Branch 22 → 23 taken 4 times.
✗ Branch 22 → 24 not taken.
✓ Branch 23 → 24 taken 1 time.
✓ Branch 23 → 25 taken 3 times.
4 if (dmaxSat <= 0.0 || dmaxSat > 150.0)
2205
1/2
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 89 taken 1 time.
1 env->ThrowError("MaskHS: maxSat must be greater than 0 and less than or equal to 150.");
2206
2207
1/2
✓ Branch 25 → 26 taken 3 times.
✗ Branch 25 → 89 not taken.
3 pixelsize = vi.ComponentSize();
2208
1/2
✓ Branch 26 → 27 taken 3 times.
✗ Branch 26 → 89 not taken.
3 bits_per_pixel = vi.BitsPerComponent();
2209 3 max_pixel_value = (1 << bits_per_pixel) - 1;
2210 3 lut_size = 1 << bits_per_pixel;
2211
2212 3 get_limits(limits, bits_per_pixel);
2213
2214
2/2
✓ Branch 28 → 29 taken 2 times.
✓ Branch 28 → 30 taken 1 time.
3 mask_low = coring ? limits.tv_range_low : 0;
2215
2/2
✓ Branch 31 → 32 taken 2 times.
✓ Branch 31 → 33 taken 1 time.
3 mask_high = coring ? limits.tv_range_hi_luma : max_pixel_value;
2216
2217
1/2
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 42 taken 3 times.
3 if (bits_per_pixel == 32) {
2218 mask_low_f = coring ? limits.tv_range_low_luma_f : limits.full_range_low_luma_f;
2219 mask_high_f = coring ? limits.tv_range_hi_luma_f : limits.full_range_hi_luma_f;
2220 }
2221
2222 3 realcalc_chroma = realcalc;
2223
4/8
✓ Branch 42 → 43 taken 3 times.
✗ Branch 42 → 89 not taken.
✓ Branch 43 → 44 taken 3 times.
✗ Branch 43 → 46 not taken.
✗ Branch 44 → 45 not taken.
✓ Branch 44 → 46 taken 3 times.
✗ Branch 47 → 48 not taken.
✓ Branch 47 → 49 taken 3 times.
3 if (vi.IsPlanar() && (bits_per_pixel > 12)) // max bitdepth is 12 for lut
2224 realcalc_chroma = true;
2225
2226 // 100% equals sat=119 (= maximal saturation of valid RGB (R=255,G=B=0)
2227 // 150% (=180) - 100% (=119) overshoot
2228 3 minSat = 1.19 * dminSat;
2229 3 maxSat = 1.19 * dmaxSat;
2230
2231
6/8
✓ Branch 49 → 50 taken 2 times.
✓ Branch 49 → 52 taken 1 time.
✓ Branch 50 → 51 taken 2 times.
✗ Branch 50 → 89 not taken.
✗ Branch 51 → 52 not taken.
✓ Branch 51 → 53 taken 2 times.
✓ Branch 54 → 55 taken 1 time.
✓ Branch 54 → 75 taken 2 times.
3 if (!(realcalc_chroma && vi.IsPlanar()))
2232 { // fill lookup tables for UV
2233 1 size_t map_size = pixelsize * lut_size * lut_size;
2234 // for 8 bit : 1 * 256 * 256 = 65536 byte
2235 // for 10 bit : 2 * 1024 * 1024 = 2 MByte
2236 // for 12 bit : 2 * 4096 * 4096 = 32 MByte
2237
1/2
✓ Branch 55 → 56 taken 1 time.
✗ Branch 55 → 89 not taken.
1 mapUV = static_cast<uint8_t*>(env->Allocate(map_size, 8, AVS_NORMAL_ALLOC)); // uint16_t for (U+V bytes), casted to uint32_t for (U+V words in non-8 bit)
2238
1/2
✗ Branch 56 → 57 not taken.
✓ Branch 56 → 58 taken 1 time.
1 if (!mapUV)
2239 env->ThrowError("Tweak: Could not reserve memory.");
2240
1/2
✓ Branch 58 → 59 taken 1 time.
✗ Branch 58 → 89 not taken.
1 env->AtExit(free_buffer, mapUV);
2241
2242 // apply mask
2243 1 double uv_range_corr = 1.0 / (1 << (bits_per_pixel - 8)); // no float here
2244
2/2
✓ Branch 74 → 60 taken 256 times.
✓ Branch 74 → 75 taken 1 time.
257 for (int u = 0; u < lut_size; u++) {
2245 256 const double destu = (u - limits.middle_chroma) * uv_range_corr; // processpixel's minSat and maxSat is for 256 range
2246 256 int ushift = u << bits_per_pixel;
2247
2/2
✓ Branch 72 → 61 taken 65536 times.
✓ Branch 72 → 73 taken 256 times.
65792 for (int v = 0; v < lut_size; v++) {
2248 65536 const double destv = (v - limits.middle_chroma) * uv_range_corr;
2249 65536 int iSat = 0; // won't be used in MaskHS; interpolation is skipped since p==0:
2250
1/2
✓ Branch 61 → 62 taken 65536 times.
✗ Branch 61 → 88 not taken.
65536 bool ppres = ProcessPixel(destv, destu, dstartHue, dendHue, maxSat, minSat, 0.0, iSat);
2251
1/2
✓ Branch 62 → 63 taken 65536 times.
✗ Branch 62 → 67 not taken.
65536 if(pixelsize==1)
2252
2/2
✓ Branch 63 → 64 taken 8900 times.
✓ Branch 63 → 65 taken 56636 times.
65536 mapUV[ushift | v] = ppres ? mask_high : mask_low;
2253 else
2254 reinterpret_cast<uint16_t *>(mapUV)[ushift | v] = ppres ? mask_high : mask_low;
2255 }
2256 }
2257 } // end of lut calculation
2258 // #define MaskPointResizing
2259 #ifndef MaskPointResizing
2260
1/2
✓ Branch 75 → 76 taken 3 times.
✗ Branch 75 → 89 not taken.
3 vi.width >>= vi.GetPlaneWidthSubsampling(PLANAR_U);
2261
1/2
✓ Branch 76 → 77 taken 3 times.
✗ Branch 76 → 89 not taken.
3 vi.height >>= vi.GetPlaneHeightSubsampling(PLANAR_U);
2262 #endif
2263
1/7
✓ Branch 77 → 78 taken 3 times.
✗ Branch 77 → 79 not taken.
✗ Branch 77 → 80 not taken.
✗ Branch 77 → 81 not taken.
✗ Branch 77 → 82 not taken.
✗ Branch 77 → 83 not taken.
✗ Branch 77 → 84 not taken.
3 switch(bits_per_pixel) {
2264 3 case 8: vi.pixel_type = VideoInfo::CS_Y8; break;
2265 case 10: vi.pixel_type = VideoInfo::CS_Y10; break;
2266 case 12: vi.pixel_type = VideoInfo::CS_Y12; break;
2267 case 14: vi.pixel_type = VideoInfo::CS_Y14; break;
2268 case 16: vi.pixel_type = VideoInfo::CS_Y16; break;
2269 case 32: vi.pixel_type = VideoInfo::CS_Y32; break;
2270 }
2271 11 }
2272
2273
2274
2275 5 PVideoFrame __stdcall MaskHS::GetFrame(int n, IScriptEnvironment* env)
2276 {
2277
1/2
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 101 not taken.
5 PVideoFrame src = child->GetFrame(n, env);
2278
1/2
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 99 not taken.
5 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
2279
2280
1/2
✓ Branch 6 → 7 taken 5 times.
✗ Branch 6 → 97 not taken.
5 uint8_t* dstp = dst->GetWritePtr();
2281
1/2
✓ Branch 8 → 9 taken 5 times.
✗ Branch 8 → 97 not taken.
5 int dst_pitch = dst->GetPitch();
2282
2283 // show mask
2284
3/6
✓ Branch 10 → 11 taken 5 times.
✗ Branch 10 → 97 not taken.
✓ Branch 11 → 12 taken 5 times.
✗ Branch 11 → 97 not taken.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 27 taken 5 times.
5 if (child->GetVideoInfo().IsYUY2()) {
2285 const uint8_t* srcp = src->GetReadPtr();
2286 const int src_pitch = src->GetPitch();
2287 const int height = src->GetHeight();
2288
2289 #ifndef MaskPointResizing
2290 const int row_size = src->GetRowSize() >> 2;
2291
2292 for (int y = 0; y < height; y++) {
2293 for (int x = 0; x < row_size; x++) {
2294 dstp[x] = mapUV[((srcp[x * 4 + 1]) << 8) | srcp[x * 4 + 3]];
2295 }
2296 srcp += src_pitch;
2297 dstp += dst_pitch;
2298 }
2299 #else
2300 const int row_size = src->GetRowSize();
2301
2302 for (int y = 0; y < height; y++) {
2303 for (int xs = 0, xd = 0; xs < row_size; xs += 4, xd += 2) {
2304 const BYTE mapped = mapY[((srcp[xs + 1]) << 8) | srcp[xs + 3]];
2305 dstp[xd] = mapped;
2306 dstp[xd + 1] = mapped;
2307 }
2308 srcp += src_pitch;
2309 dstp += dst_pitch;
2310 }
2311 #endif
2312 }
2313
3/6
✓ Branch 28 → 29 taken 5 times.
✗ Branch 28 → 97 not taken.
✓ Branch 29 → 30 taken 5 times.
✗ Branch 29 → 97 not taken.
✓ Branch 30 → 31 taken 5 times.
✗ Branch 30 → 91 not taken.
5 else if (child->GetVideoInfo().IsPlanar()) {
2314
1/2
✓ Branch 32 → 33 taken 5 times.
✗ Branch 32 → 97 not taken.
5 const int srcu_pitch = src->GetPitch(PLANAR_U);
2315
1/2
✓ Branch 34 → 35 taken 5 times.
✗ Branch 34 → 97 not taken.
5 const uint8_t* srcpu = src->GetReadPtr(PLANAR_U);
2316
1/2
✓ Branch 36 → 37 taken 5 times.
✗ Branch 36 → 97 not taken.
5 const uint8_t* srcpv = src->GetReadPtr(PLANAR_V);
2317
1/2
✓ Branch 38 → 39 taken 5 times.
✗ Branch 38 → 97 not taken.
5 const int width = src->GetRowSize(PLANAR_U) / pixelsize;
2318
1/2
✓ Branch 40 → 41 taken 5 times.
✗ Branch 40 → 97 not taken.
5 const int heightu = src->GetHeight(PLANAR_U);
2319
2320 #ifndef MaskPointResizing
2321
2/2
✓ Branch 41 → 42 taken 3 times.
✓ Branch 41 → 77 taken 2 times.
5 if(realcalc_chroma) {
2322
1/2
✓ Branch 42 → 43 taken 3 times.
✗ Branch 42 → 44 not taken.
3 double uv_range_corr = (pixelsize == 4) ? 255.0 : 1.0 / (1 << (bits_per_pixel - 8));
2323
1/2
✓ Branch 45 → 46 taken 3 times.
✗ Branch 45 → 56 not taken.
3 if(pixelsize == 1) {
2324
2/2
✓ Branch 55 → 47 taken 6 times.
✓ Branch 55 → 91 taken 3 times.
9 for (int y = 0; y < heightu; ++y) {
2325
2/2
✓ Branch 53 → 48 taken 36 times.
✓ Branch 53 → 54 taken 6 times.
42 for (int x = 0; x < width; ++x) {
2326 36 const double destu = srcpu[x] - limits.middle_chroma;
2327 36 const double destv = srcpv[x] - limits.middle_chroma;
2328 36 int iSat = 0; // won't be used in MaskHS; interpolation is skipped since p==0:
2329
1/2
✓ Branch 48 → 49 taken 36 times.
✗ Branch 48 → 94 not taken.
36 bool ppres = ProcessPixel(destv * uv_range_corr, destu * uv_range_corr, dstartHue, dendHue, maxSat, minSat, 0.0, iSat);
2330
2/2
✓ Branch 49 → 50 taken 16 times.
✓ Branch 49 → 51 taken 20 times.
36 dstp[x] = ppres ? mask_high : mask_low;
2331 }
2332 6 dstp += dst_pitch;
2333 6 srcpu += srcu_pitch;
2334 6 srcpv += srcu_pitch;
2335 }
2336 }
2337 else if (pixelsize == 2) {
2338 for (int y = 0; y < heightu; ++y) {
2339 for (int x = 0; x < width; ++x) {
2340 const double destu = (reinterpret_cast<const uint16_t *>(srcpu)[x] - limits.middle_chroma);
2341 const double destv = (reinterpret_cast<const uint16_t *>(srcpv)[x] - limits.middle_chroma);
2342 int iSat = 0; // won't be used in MaskHS; interpolation is skipped since p==0:
2343 bool ppres = ProcessPixel(destv * uv_range_corr, destu * uv_range_corr, dstartHue, dendHue, maxSat, minSat, 0.0, iSat);
2344 reinterpret_cast<uint16_t *>(dstp)[x] = ppres ? mask_high : mask_low;
2345 }
2346 dstp += dst_pitch;
2347 srcpu += srcu_pitch;
2348 srcpv += srcu_pitch;
2349 }
2350 } else { // pixelsize == 4
2351 for (int y = 0; y < heightu; ++y) {
2352 for (int x = 0; x < width; ++x) {
2353 const double destu = (reinterpret_cast<const float *>(srcpu)[x] - limits.middle_chroma_f);
2354 const double destv = (reinterpret_cast<const float *>(srcpv)[x] - limits.middle_chroma_f);
2355 int iSat = 0; // won't be used in MaskHS; interpolation is skipped since p==0:
2356 bool ppres = ProcessPixel(destv * uv_range_corr, destu * uv_range_corr, dstartHue, dendHue, maxSat, minSat, 0.0, iSat);
2357 reinterpret_cast<float *>(dstp)[x] = ppres ? mask_high_f : mask_low_f;
2358 }
2359 dstp += dst_pitch;
2360 srcpu += srcu_pitch;
2361 srcpv += srcu_pitch;
2362 }
2363 }
2364
2365 } else {
2366 // use LUT
2367
1/2
✓ Branch 77 → 78 taken 2 times.
✗ Branch 77 → 84 not taken.
2 if(pixelsize==1) {
2368
2/2
✓ Branch 83 → 79 taken 4 times.
✓ Branch 83 → 91 taken 2 times.
6 for (int y = 0; y < heightu; ++y) {
2369
2/2
✓ Branch 81 → 80 taken 28 times.
✓ Branch 81 → 82 taken 4 times.
32 for (int x = 0; x < width; ++x) {
2370 28 dstp[x] = mapUV[((srcpu[x]) << 8) | srcpv[x]];
2371 }
2372 4 dstp += dst_pitch;
2373 4 srcpu += srcu_pitch;
2374 4 srcpv += srcu_pitch;
2375 }
2376 }
2377 else if (pixelsize == 2) {
2378 for (int y = 0; y < heightu; ++y) {
2379 for (int x = 0; x < width; ++x) {
2380 reinterpret_cast<uint16_t *>(dstp)[x] =
2381 reinterpret_cast<uint16_t *>(mapUV)[((reinterpret_cast<const uint16_t *>(srcpu)[x]) << bits_per_pixel) | reinterpret_cast<const uint16_t *>(srcpv)[x]];
2382 }
2383 dstp += dst_pitch;
2384 srcpu += srcu_pitch;
2385 srcpv += srcu_pitch;
2386 }
2387 } // no lut for float (and for 14-16 bit)
2388 }
2389 #else
2390 const int swidth = child->GetVideoInfo().GetPlaneWidthSubsampling(PLANAR_U);
2391 const int sheight = child->GetVideoInfo().GetPlaneHeightSubsampling(PLANAR_U);
2392 const int sw = 1 << swidth;
2393 const int sh = 1 << sheight;
2394
2395 const int dpitch = dst_pitch << sheight;
2396 for (int y = 0; y < heightu; ++y) {
2397 for (int x = 0; x < row_sizeu; ++x) {
2398 const BYTE mapped = mapY[((srcpu[x]) << 8) | srcpv[x]];
2399 const int sx = x << swidth;
2400
2401 for (int lumv = 0; lumv < sh; ++lumv) {
2402 const int sy = lumv*dst_pitch + sx;
2403
2404 for (int lumh = 0; lumh < sw; ++lumh) {
2405 dstp[sy + lumh] = mapped;
2406 }
2407 }
2408 }
2409 dstp += dpitch;
2410 srcpu += srcu_pitch;
2411 srcpv += srcu_pitch;
2412 }
2413 #endif
2414 }
2415 5 return dst;
2416 5 }
2417
2418
2419
2420 AVSValue __cdecl MaskHS::Create(AVSValue args, void* , IScriptEnvironment* env)
2421 {
2422 return new MaskHS(args[0].AsClip(),
2423 args[1].AsDblDef(0.0), // startHue
2424 args[2].AsDblDef(360.0), // endHue
2425 args[3].AsDblDef(150.0), // maxSat
2426 args[4].AsDblDef(0.0), // minSat
2427 args[5].AsBool(false), // coring
2428 args[6].AsBool(false), // realcalc
2429 env);
2430 }
2431
2432