GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 56.4% 1028 / 0 / 1822
Functions: 63.8% 37 / 0 / 58
Branches: 39.7% 834 / 0 / 2103

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 10 static void __cdecl free_buffer(void* buff, IScriptEnvironment* env)
120 {
121
1/2
✓ Branch 2 → 3 taken 10 times.
✗ Branch 2 → 4 not taken.
10 if (buff) {
122 10 static_cast<IScriptEnvironment2*>(env)->Free(buff);
123 }
124 10 }
125
126 // Helper for Limits, MaskHS, Tweak
127 20 static void get_limits(luma_chroma_limits_t &d, int bits_per_pixel) {
128 20 int tv_range_lo_luma_8 = 16;
129 20 int tv_range_hi_luma_8 = 235;
130 20 int tv_range_lo_chroma_8 = tv_range_lo_luma_8;
131 20 int tv_range_hi_chroma_8 = 240;
132
133
2/2
✓ Branch 2 → 3 taken 5 times.
✓ Branch 2 → 4 taken 15 times.
20 if (bits_per_pixel == 32) {
134 5 d.tv_range_low_luma_f = tv_range_lo_luma_8 / 255.0f;
135 5 d.tv_range_hi_luma_f = tv_range_hi_luma_8 / 255.0f;
136 5 d.full_range_low_luma_f = 0.0f;
137 5 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 5 d.middle_chroma_f = 0.0f;
142 #endif
143 5 d.tv_range_low_chroma_f = (tv_range_lo_chroma_8 - 128) / 255.0f + d.middle_chroma_f; // -112
144 5 d.tv_range_hi_chroma_f = (tv_range_hi_chroma_8 - 128) / 255.0f + d.middle_chroma_f; // 112
145 5 d.full_range_low_chroma_f = d.middle_chroma_f - 0.5f; // -0.5..0.5 or 0..1.0
146 5 d.full_range_hi_chroma_f = d.middle_chroma_f + 0.5f;
147
148 5 d.range_luma_f = d.tv_range_hi_luma_f - d.tv_range_low_luma_f;
149 5 d.range_chroma_f = d.tv_range_hi_chroma_f - d.tv_range_low_chroma_f;
150 }
151 else {
152 15 d.tv_range_low = tv_range_lo_luma_8 << (bits_per_pixel - 8); // 16-240,64-960, 256-3852,... 4096-61692
153 15 d.tv_range_hi_luma = tv_range_hi_luma_8 << (bits_per_pixel - 8);
154 15 d.tv_range_hi_chroma = tv_range_hi_chroma_8 << (bits_per_pixel - 8);
155 15 d.middle_chroma = 1 << (bits_per_pixel - 1); // 128
156 15 d.range_luma = d.tv_range_hi_luma - d.tv_range_low; // 219
157 15 d.range_chroma = d.tv_range_hi_chroma - d.tv_range_low; // 224
158 }
159 20 }
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 276 → 277 not taken.
✗ Branch 276 → 278 not taken.
✗ Branch 383 → 384 not taken.
✗ Branch 383 → 385 not taken.
✗ Branch 486 → 487 not taken.
✗ Branch 486 → 488 not taken.
✗ Branch 573 → 574 not taken.
✓ Branch 573 → 575 taken 10 times.
✗ Branch 612 → 613 not taken.
✗ Branch 612 → 614 not taken.
✗ Branch 719 → 720 not taken.
✗ Branch 719 → 721 not taken.
✗ Branch 822 → 823 not taken.
✗ Branch 822 → 824 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
1/16
✗ Branch 240 → 241 not taken.
✗ Branch 240 → 242 not taken.
✗ Branch 386 → 387 not taken.
✗ Branch 386 → 388 not taken.
✗ Branch 418 → 419 not taken.
✗ Branch 418 → 420 not taken.
✗ Branch 450 → 451 not taken.
✗ Branch 450 → 452 not taken.
✗ Branch 576 → 577 not taken.
✓ Branch 576 → 578 taken 10 times.
✗ Branch 722 → 723 not taken.
✗ Branch 722 → 724 not taken.
✗ Branch 754 → 755 not taken.
✗ Branch 754 → 756 not taken.
✗ Branch 786 → 787 not taken.
✗ Branch 786 → 788 not taken.
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 248 → 249 not taken.
✗ Branch 248 → 258 not taken.
✗ Branch 279 → 280 not taken.
✗ Branch 279 → 289 not taken.
✗ Branch 394 → 395 not taken.
✗ Branch 394 → 404 not taken.
✗ Branch 426 → 427 not taken.
✗ Branch 426 → 436 not taken.
✗ Branch 458 → 459 not taken.
✗ Branch 458 → 468 not taken.
✗ Branch 489 → 490 not taken.
✗ Branch 489 → 499 not taken.
✗ Branch 513 → 514 not taken.
✗ Branch 513 → 523 not taken.
✗ Branch 537 → 538 not taken.
✗ Branch 537 → 547 not taken.
✗ Branch 584 → 585 not taken.
✓ Branch 584 → 594 taken 10 times.
✗ Branch 615 → 616 not taken.
✗ Branch 615 → 625 not taken.
✗ Branch 730 → 731 not taken.
✗ Branch 730 → 740 not taken.
✗ Branch 762 → 763 not taken.
✗ Branch 762 → 772 not taken.
✗ Branch 794 → 795 not taken.
✗ Branch 794 → 804 not taken.
✗ Branch 825 → 826 not taken.
✗ Branch 825 → 835 not taken.
✗ Branch 849 → 850 not taken.
✗ Branch 849 → 859 not taken.
✗ Branch 873 → 874 not taken.
✗ Branch 873 → 883 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 318 → 319 not taken.
✗ Branch 318 → 328 not taken.
✗ Branch 654 → 655 not taken.
✓ Branch 654 → 664 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
4/8
✗ Branch 328 → 329 not taken.
✗ Branch 328 → 330 not taken.
✗ Branch 349 → 350 not taken.
✗ Branch 349 → 351 not taken.
✓ Branch 664 → 665 taken 2 times.
✓ Branch 664 → 666 taken 8 times.
✓ Branch 685 → 686 taken 2 times.
✓ Branch 685 → 687 taken 8 times.
40 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 → 129 not taken.
✓ Branch 3 → 4 taken 4 times.
✗ Branch 3 → 127 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 → 130 not taken.
4 pixelsize = vi.ComponentSize();
239
1/2
✓ Branch 14 → 15 taken 4 times.
✗ Branch 14 → 130 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 → 130 not taken.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 28 taken 4 times.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 130 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 31 not taken.
✓ Branch 28 → 29 taken 4 times.
✗ Branch 28 → 130 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 → 130 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 → 119 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 → 130 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 → 130 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 118 → 58 taken 66048 times.
✓ Branch 118 → 126 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
2/2
✓ Branch 64 → 65 taken 8249 times.
✓ Branch 64 → 66 taken 57799 times.
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 72 → 73 taken 256 times.
✓ Branch 72 → 82 taken 65792 times.
66048 if (coring)
304
1/2
✗ Branch 73 → 74 not taken.
✓ Branch 73 → 75 taken 256 times.
512 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
1/2
✗ Branch 82 → 83 not taken.
✓ Branch 82 → 84 taken 65792 times.
131584 luma = clamp(int(p + 0.5), 0, max_pixel_value);
307
308
2/2
✓ Branch 91 → 92 taken 512 times.
✓ Branch 91 → 93 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 94 → 95 taken 65792 times.
✓ Branch 94 → 117 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 95 → 96 taken 256 times.
✓ Branch 95 → 105 taken 65536 times.
65792 if (coring)
317
2/2
✓ Branch 96 → 97 taken 31 times.
✓ Branch 96 → 98 taken 225 times.
512 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 114 → 115 taken 256 times.
✓ Branch 114 → 116 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 119 → 120 not taken.
✓ Branch 119 → 126 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 → 900 not taken.
4 env->MakeWritable(&frame);
345
1/2
✓ Branch 6 → 7 taken 4 times.
✗ Branch 6 → 900 not taken.
4 BYTE* p = frame->GetWritePtr();
346
1/2
✓ Branch 8 → 9 taken 4 times.
✗ Branch 8 → 900 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 → 900 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 → 900 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 → 900 not taken.
✗ Branch 131 → 132 not taken.
✓ Branch 131 → 134 taken 3 times.
✗ Branch 132 → 133 not taken.
✗ Branch 132 → 900 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 → 900 not taken.
3 const int UVpitch = frame->GetPitch(PLANAR_U);
531
1/2
✓ Branch 153 → 154 taken 3 times.
✗ Branch 153 → 900 not taken.
3 p = frame->GetWritePtr(PLANAR_U);
532
1/2
✓ Branch 155 → 156 taken 3 times.
✗ Branch 155 → 900 not taken.
3 const int w = frame->GetRowSize(PLANAR_U) / pixelsize;
533
1/2
✓ Branch 157 → 158 taken 3 times.
✗ Branch 157 → 900 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 → 900 not taken.
2 p = frame->GetWritePtr(PLANAR_V);
542
2/2
✓ Branch 172 → 168 taken 2 times.
✓ Branch 172 → 898 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 → 900 not taken.
1 p = frame->GetWritePtr(PLANAR_V);
557
2/2
✓ Branch 186 → 182 taken 3 times.
✓ Branch 186 → 898 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 → 562 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 562 → 563 taken 1 time.
✗ Branch 562 → 900 not taken.
✗ Branch 563 → 564 not taken.
✓ Branch 563 → 566 taken 1 time.
✗ Branch 564 → 565 not taken.
✗ Branch 564 → 900 not taken.
✗ Branch 565 → 566 not taken.
✗ Branch 565 → 567 not taken.
✓ Branch 568 → 569 taken 1 time.
✗ Branch 568 → 700 not taken.
1 if (vi.IsYUV() || vi.IsYUVA()) { // planar YUV (incl Y only)
717 // luma. with or w/o gamma
718
1/2
✓ Branch 569 → 570 taken 1 time.
✗ Branch 569 → 609 not taken.
1 if (use_gamma) {
719
2/2
✓ Branch 608 → 571 taken 2 times.
✓ Branch 608 → 640 taken 1 time.
3 for (int y = 0; y < vi.height; ++y) {
720
2/2
✓ Branch 606 → 572 taken 10 times.
✓ Branch 606 → 607 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 640 → 641 taken 1 time.
✗ Branch 640 → 898 not taken.
1 if (need_chroma) {
739
1/2
✓ Branch 642 → 643 taken 1 time.
✗ Branch 642 → 900 not taken.
1 const int UVpitch = frame->GetPitch(PLANAR_U);
740
1/2
✓ Branch 644 → 645 taken 1 time.
✗ Branch 644 → 900 not taken.
1 const int w = frame->GetRowSize(PLANAR_U) / pixelsize;
741
1/2
✓ Branch 646 → 647 taken 1 time.
✗ Branch 646 → 900 not taken.
1 const int h = frame->GetHeight(PLANAR_U);
742
1/2
✓ Branch 648 → 649 taken 1 time.
✗ Branch 648 → 900 not taken.
1 p = frame->GetWritePtr(PLANAR_U);
743
1/2
✓ Branch 650 → 651 taken 1 time.
✗ Branch 650 → 900 not taken.
1 BYTE* q = frame->GetWritePtr(PLANAR_V);
744
2/2
✓ Branch 699 → 652 taken 2 times.
✓ Branch 699 → 898 taken 1 time.
3 for (int y = 0; y < h; ++y) {
745
2/2
✓ Branch 697 → 653 taken 10 times.
✓ Branch 697 → 698 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 675 → 676 not taken.
✓ Branch 675 → 685 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 2 static void rgbadjust_read_conditional(IScriptEnvironment* env, RGBAdjustConfig* config, const char * condVarSuffix)
824 {
825
4/8
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 147 not taken.
✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 150 not taken.
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 151 not taken.
✓ Branch 11 → 12 taken 2 times.
✗ Branch 11 → 13 not taken.
4 READ_CONDITIONAL(0, r, scale, condVarSuffix);
826
4/8
✓ Branch 16 → 17 taken 2 times.
✗ Branch 16 → 154 not taken.
✓ Branch 18 → 19 taken 2 times.
✗ Branch 18 → 157 not taken.
✓ Branch 22 → 23 taken 2 times.
✗ Branch 22 → 158 not taken.
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 2 times.
4 READ_CONDITIONAL(1, g, scale, condVarSuffix);
827
4/8
✓ Branch 28 → 29 taken 2 times.
✗ Branch 28 → 161 not taken.
✓ Branch 30 → 31 taken 2 times.
✗ Branch 30 → 164 not taken.
✓ Branch 34 → 35 taken 2 times.
✗ Branch 34 → 165 not taken.
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 2 times.
4 READ_CONDITIONAL(2, b, scale, condVarSuffix);
828
5/8
✓ Branch 40 → 41 taken 2 times.
✗ Branch 40 → 168 not taken.
✓ Branch 42 → 43 taken 2 times.
✗ Branch 42 → 171 not taken.
✓ Branch 46 → 47 taken 2 times.
✗ Branch 46 → 172 not taken.
✓ Branch 47 → 48 taken 1 time.
✓ Branch 47 → 49 taken 1 time.
4 READ_CONDITIONAL(3, a, scale, condVarSuffix);
829
830
4/8
✓ Branch 52 → 53 taken 2 times.
✗ Branch 52 → 175 not taken.
✓ Branch 54 → 55 taken 2 times.
✗ Branch 54 → 178 not taken.
✓ Branch 58 → 59 taken 2 times.
✗ Branch 58 → 179 not taken.
✗ Branch 59 → 60 not taken.
✓ Branch 59 → 61 taken 2 times.
4 READ_CONDITIONAL(0, rb, bias, condVarSuffix);
831
4/8
✓ Branch 64 → 65 taken 2 times.
✗ Branch 64 → 182 not taken.
✓ Branch 66 → 67 taken 2 times.
✗ Branch 66 → 185 not taken.
✓ Branch 70 → 71 taken 2 times.
✗ Branch 70 → 186 not taken.
✓ Branch 71 → 72 taken 2 times.
✗ Branch 71 → 73 not taken.
4 READ_CONDITIONAL(1, gb, bias, condVarSuffix);
832
4/8
✓ Branch 76 → 77 taken 2 times.
✗ Branch 76 → 189 not taken.
✓ Branch 78 → 79 taken 2 times.
✗ Branch 78 → 192 not taken.
✓ Branch 82 → 83 taken 2 times.
✗ Branch 82 → 193 not taken.
✗ Branch 83 → 84 not taken.
✓ Branch 83 → 85 taken 2 times.
4 READ_CONDITIONAL(2, bb, bias, condVarSuffix);
833
5/8
✓ Branch 88 → 89 taken 2 times.
✗ Branch 88 → 196 not taken.
✓ Branch 90 → 91 taken 2 times.
✗ Branch 90 → 199 not taken.
✓ Branch 94 → 95 taken 2 times.
✗ Branch 94 → 200 not taken.
✓ Branch 95 → 96 taken 1 time.
✓ Branch 95 → 97 taken 1 time.
4 READ_CONDITIONAL(3, ab, bias, condVarSuffix);
834
835
4/8
✓ Branch 100 → 101 taken 2 times.
✗ Branch 100 → 203 not taken.
✓ Branch 102 → 103 taken 2 times.
✗ Branch 102 → 206 not taken.
✓ Branch 106 → 107 taken 2 times.
✗ Branch 106 → 207 not taken.
✗ Branch 107 → 108 not taken.
✓ Branch 107 → 109 taken 2 times.
4 READ_CONDITIONAL(0, rg, gamma, condVarSuffix);
836
4/8
✓ Branch 112 → 113 taken 2 times.
✗ Branch 112 → 210 not taken.
✓ Branch 114 → 115 taken 2 times.
✗ Branch 114 → 213 not taken.
✓ Branch 118 → 119 taken 2 times.
✗ Branch 118 → 214 not taken.
✗ Branch 119 → 120 not taken.
✓ Branch 119 → 121 taken 2 times.
4 READ_CONDITIONAL(1, gg, gamma, condVarSuffix);
837
4/8
✓ Branch 124 → 125 taken 2 times.
✗ Branch 124 → 217 not taken.
✓ Branch 126 → 127 taken 2 times.
✗ Branch 126 → 220 not taken.
✓ Branch 130 → 131 taken 2 times.
✗ Branch 130 → 221 not taken.
✓ Branch 131 → 132 taken 2 times.
✗ Branch 131 → 133 not taken.
4 READ_CONDITIONAL(2, bg, gamma, condVarSuffix);
838
5/8
✓ Branch 136 → 137 taken 2 times.
✗ Branch 136 → 224 not taken.
✓ Branch 138 → 139 taken 2 times.
✗ Branch 138 → 227 not taken.
✓ Branch 142 → 143 taken 2 times.
✗ Branch 142 → 228 not taken.
✓ Branch 143 → 144 taken 1 time.
✓ Branch 143 → 145 taken 1 time.
4 READ_CONDITIONAL(3, ag, gamma, condVarSuffix);
839 2 }
840
841 #undef READ_CONDITIONAL
842
843
844
845 14 RGBAdjust::~RGBAdjust()
846 {
847
2/2
✓ Branch 2 → 3 taken 9 times.
✓ Branch 2 → 5 taken 5 times.
14 if (map_holder)
848
1/2
✓ Branch 3 → 4 taken 9 times.
✗ Branch 3 → 5 not taken.
9 delete[] map_holder;
849 14 }
850
851 16 void RGBAdjust::CheckAndConvertParams(RGBAdjustConfig &config, IScriptEnvironment *env)
852 {
853
4/8
✓ Branch 2 → 3 taken 16 times.
✗ Branch 2 → 6 not taken.
✓ Branch 3 → 4 taken 16 times.
✗ Branch 3 → 6 not taken.
✓ Branch 4 → 5 taken 16 times.
✗ Branch 4 → 6 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 16 times.
16 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 16 }
856
857 115440 static __inline float RGBAdjust_processPixel(const float val, const double c0, const double c1, const double c2)
858 {
859 115440 const double pixel_max = 1.0;
860
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 115440 times.
230880 return (float)(pow(clamp((c0 + val * c1) / pixel_max, 0.0, 1.0), c2));
861 }
862
863 32 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 32 times.
32 if (!use_lut)
865 return;
866
867 32 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 29 times.
32 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 → 14 not taken.
3 if (bits_per_pixel == 8) {
875
2/2
✓ Branch 13 → 4 taken 196608 times.
✓ Branch 13 → 25 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
2/2
✓ Branch 4 → 5 taken 1149 times.
✓ Branch 4 → 6 taken 195459 times.
393216 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 29 set_map = [](BYTE* map, int lookup_size, int bits_per_pixel, float dither_strength, const double c0, const double c1, const double c2) {
890 29 double pixel_max = (1 << bits_per_pixel) - 1;
891
2/2
✓ Branch 2 → 3 taken 22 times.
✓ Branch 2 → 14 taken 7 times.
29 if (bits_per_pixel == 8) {
892
2/2
✓ Branch 13 → 4 taken 5632 times.
✓ Branch 13 → 25 taken 22 times.
5654 for (int i = 0; i < lookup_size; ++i) { // fix of bug introduced in an earlier refactor was: i < 256 * 256
893
2/2
✓ Branch 4 → 5 taken 73 times.
✓ Branch 4 → 6 taken 5559 times.
11264 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 24 → 15 taken 458752 times.
✓ Branch 24 → 25 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
2/2
✓ Branch 15 → 16 taken 14243 times.
✓ Branch 15 → 17 taken 444509 times.
917504 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 29 };
902 }
903
904 32 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 14 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 14 bool _analyze, bool _dither, bool _conditional, const char *_condVarSuffix, IScriptEnvironment* env)
911
2/4
✓ Branch 2 → 3 taken 14 times.
✗ Branch 2 → 54 not taken.
✓ Branch 3 → 4 taken 14 times.
✗ Branch 3 → 52 not taken.
14 : GenericVideoFilter(_child), analyze(_analyze), dither(_dither), conditional(_conditional), condVarSuffix(_condVarSuffix)
912 {
913 // one buffer for all maps
914 14 map_holder = nullptr;
915
916
2/4
✓ Branch 5 → 6 taken 14 times.
✗ Branch 5 → 55 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 14 times.
14 if (!vi.IsRGB())
917 env->ThrowError("RGBAdjust requires RGB input");
918
919 14 config.rgba[0].scale = r;
920 14 config.rgba[1].scale = g;
921 14 config.rgba[2].scale = b;
922 14 config.rgba[3].scale = a;
923 // bias
924 14 config.rgba[0].bias = rb;
925 14 config.rgba[1].bias = gb;
926 14 config.rgba[2].bias = bb;
927 14 config.rgba[3].bias = ab;
928 // gammas
929 14 config.rgba[0].gamma = rg;
930 14 config.rgba[1].gamma = gg;
931 14 config.rgba[2].gamma = bg;
932 14 config.rgba[3].gamma = ag;
933
934 14 config.rgba[0].changed = false;
935 14 config.rgba[1].changed = false;
936 14 config.rgba[2].changed = false;
937 14 config.rgba[3].changed = false;
938
939
1/2
✓ Branch 8 → 9 taken 14 times.
✗ Branch 8 → 55 not taken.
14 CheckAndConvertParams(config, env);
940
941
1/2
✓ Branch 9 → 10 taken 14 times.
✗ Branch 9 → 55 not taken.
14 pixelsize = vi.ComponentSize();
942
1/2
✓ Branch 10 → 11 taken 14 times.
✗ Branch 10 → 55 not taken.
14 bits_per_pixel = vi.BitsPerComponent(); // 8,10..16
943
944 14 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 7 times.
✓ Branch 12 → 14 taken 7 times.
14 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 9 times.
✓ Branch 15 → 17 taken 5 times.
14 max_pixel_value = (pixelsize == 4) ? 255 : (1 << bits_per_pixel) - 1; // n/a for float formats
952 14 dither_strength = 1.0f; // fixed, not used
953
954 14 use_lut = bits_per_pixel != 32; // for float: realtime (todo)
955
956
2/2
✓ Branch 18 → 19 taken 5 times.
✓ Branch 18 → 20 taken 9 times.
14 if (!use_lut)
957 5 dither = false;
958
959
2/2
✓ Branch 20 → 21 taken 9 times.
✓ Branch 20 → 51 taken 5 times.
14 if(use_lut) {
960
8/12
✓ Branch 21 → 22 taken 9 times.
✗ Branch 21 → 55 not taken.
✓ Branch 22 → 23 taken 3 times.
✓ Branch 22 → 27 taken 6 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.
9 number_of_maps = (vi.IsRGB24() || vi.IsRGB48() || vi.IsPlanarRGB()) ? 3 : 4;
961 9 int one_bufsize = pixelsize * real_lookup_size;
962
2/2
✓ Branch 29 → 30 taken 1 time.
✓ Branch 29 → 31 taken 8 times.
9 if (dither) one_bufsize *= 256;
963
964
1/2
✓ Branch 31 → 32 taken 9 times.
✗ Branch 31 → 55 not taken.
9 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 7 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 44 taken 2 times.
9 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 9 maps[0] = map_holder;
977 9 maps[1] = maps[0] + one_bufsize;
978 9 maps[2] = maps[1] + one_bufsize;
979
2/2
✓ Branch 44 → 45 taken 2 times.
✓ Branch 44 → 46 taken 7 times.
9 maps[3] = number_of_maps == 4 ? maps[2] + one_bufsize : nullptr;
980
981
2/2
✓ Branch 50 → 48 taken 29 times.
✓ Branch 50 → 51 taken 9 times.
38 for (int plane = 0; plane < number_of_maps; plane++) {
982
1/2
✓ Branch 48 → 49 taken 29 times.
✗ Branch 48 → 55 not taken.
29 rgbadjust_create_lut(maps[plane], plane, config);
983 }
984 }
985 14 }
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 1 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
2/2
✓ Branch 6 → 3 taken 3 times.
✓ Branch 6 → 7 taken 1 time.
4 for (int i = 0; i < 3; i++) {
1016 3 rgbplanedata.data[i].real_max = std::numeric_limits<float>::min();
1017 3 rgbplanedata.data[i].real_min = std::numeric_limits<float>::max();
1018 3 rgbplanedata.data[i].sum = 0.0;
1019 }
1020
1021
2/2
✓ Branch 48 → 8 taken 120 times.
✓ Branch 48 → 49 taken 1 time.
121 for (int y = 0; y < height; y++) {
1022
2/2
✓ Branch 46 → 9 taken 38400 times.
✓ Branch 46 → 47 taken 120 times.
38520 for (int x = 0; x < width; x++) {
1023 // convert range 0..1 to 0..65535 for loose_min/max fake histogram
1024 38400 float r = reinterpret_cast<const float*>(srcpR)[x];
1025 38400 float g = reinterpret_cast<const float*>(srcpG)[x];
1026 38400 float b = reinterpret_cast<const float*>(srcpB)[x];
1027
2/2
✓ Branch 9 → 10 taken 149 times.
✓ Branch 9 → 11 taken 38251 times.
38400 int ri = (int)(clamp(r * 65535.0f + 0.5f, 0.0f, 65535.0f));
1028
2/2
✓ Branch 17 → 18 taken 150 times.
✓ Branch 17 → 19 taken 38250 times.
38400 int gi = (int)(clamp(g * 65535.0f + 0.5f, 0.0f, 65535.0f));
1029
2/2
✓ Branch 25 → 26 taken 150 times.
✓ Branch 25 → 27 taken 38250 times.
38400 int bi = (int)(clamp(b * 65535.0f + 0.5f, 0.0f, 65535.0f));
1030
2/2
✓ Branch 33 → 34 taken 11 times.
✓ Branch 33 → 35 taken 38389 times.
38400 if (r > rgbplanedata.data[0].real_max) rgbplanedata.data[0].real_max = r;
1031
2/2
✓ Branch 35 → 36 taken 7 times.
✓ Branch 35 → 37 taken 38393 times.
38400 if (r < rgbplanedata.data[0].real_min) rgbplanedata.data[0].real_min = r;
1032 38400 rgbplanedata.data[0].sum += r;
1033
2/2
✓ Branch 37 → 38 taken 34 times.
✓ Branch 37 → 39 taken 38366 times.
38400 if (g > rgbplanedata.data[1].real_max) rgbplanedata.data[1].real_max = g;
1034
2/2
✓ Branch 39 → 40 taken 3 times.
✓ Branch 39 → 41 taken 38397 times.
38400 if (g < rgbplanedata.data[1].real_min) rgbplanedata.data[1].real_min = g;
1035 38400 rgbplanedata.data[1].sum += g;
1036
2/2
✓ Branch 41 → 42 taken 16 times.
✓ Branch 41 → 43 taken 38384 times.
38400 if (b > rgbplanedata.data[2].real_max) rgbplanedata.data[2].real_max = b;
1037
2/2
✓ Branch 43 → 44 taken 4 times.
✓ Branch 43 → 45 taken 38396 times.
38400 if (b < rgbplanedata.data[2].real_min) rgbplanedata.data[2].real_min = b;
1038 38400 rgbplanedata.data[2].sum += b;
1039 38400 accum_r[ri]++;
1040 38400 accum_g[gi]++;
1041 38400 accum_b[bi]++;
1042 }
1043 120 srcpR += pitch;
1044 120 srcpG += pitch;
1045 120 srcpB += pitch;
1046 }
1047 1 }
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 8 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 8 int _y = 0;
1069 8 int _dither = 0;
1070 8 pixel_t *dstp = reinterpret_cast<pixel_t *>(dstp8);
1071 8 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 130 times.
✓ Branch 7 → 8 taken 5 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.
145 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 38456 times.
✓ Branch 5 → 6 taken 130 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.
38636 for (int x = 0; x < width; x++) {
1077 if (dither)
1078 21 _dither = ditherMap[(x & 0x0f) | _y];
1079 38499 dstp[x * pixel_step + 0] = reinterpret_cast<pixel_t *>(mapB)[dither ? dstp[x * pixel_step + 0] << 8 | _dither : dstp[x * pixel_step + 0]];
1080 38499 dstp[x * pixel_step + 1] = reinterpret_cast<pixel_t *>(mapG)[dither ? dstp[x * pixel_step + 1] << 8 | _dither : dstp[x * pixel_step + 1]];
1081 38499 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 137 dstp += pitch;
1086 }
1087 8 }
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 14 PVideoFrame __stdcall RGBAdjust::GetFrame(int n, IScriptEnvironment* env)
1122 {
1123
1/2
✓ Branch 3 → 4 taken 14 times.
✗ Branch 3 → 231 not taken.
14 PVideoFrame frame = child->GetFrame(n, env);
1124
1/2
✓ Branch 4 → 5 taken 14 times.
✗ Branch 4 → 229 not taken.
14 env->MakeWritable(&frame);
1125
1/2
✓ Branch 6 → 7 taken 14 times.
✗ Branch 6 → 229 not taken.
14 BYTE* p = frame->GetWritePtr();
1126
1/2
✓ Branch 8 → 9 taken 14 times.
✗ Branch 8 → 229 not taken.
14 const int pitch = frame->GetPitch();
1127
1128 14 int w = vi.width;
1129 14 int h = vi.height;
1130
1131 14 RGBAdjustConfig local_config = config;
1132
1133 // Read conditional variables
1134 14 local_config.rgba[0].changed = false;
1135 14 local_config.rgba[1].changed = false;
1136 14 local_config.rgba[2].changed = false;
1137 14 local_config.rgba[3].changed = false;
1138
2/2
✓ Branch 9 → 10 taken 2 times.
✓ Branch 9 → 11 taken 12 times.
14 if (conditional)
1139
1/2
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 229 not taken.
2 rgbadjust_read_conditional(env, &local_config, condVarSuffix);
1140
1141 14 BYTE *maps_live[4] = { nullptr };
1142 14 BYTE *maps_local[4] = { nullptr }; // for local lut table allocation, don't overwrite common buffer
1143
2/2
✓ Branch 13 → 12 taken 56 times.
✓ Branch 13 → 14 taken 14 times.
70 for (int i = 0; i < 4; i++)
1144 56 maps_live[i] = maps[i];
1145
1146
5/8
✓ Branch 14 → 15 taken 12 times.
✓ Branch 14 → 18 taken 2 times.
✓ Branch 15 → 16 taken 12 times.
✗ Branch 15 → 18 not taken.
✓ Branch 16 → 17 taken 12 times.
✗ Branch 16 → 18 not taken.
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 28 taken 12 times.
14 if (local_config.rgba[0].changed || local_config.rgba[1].changed || local_config.rgba[2].changed || local_config.rgba[3].changed) {
1147
1/2
✓ Branch 18 → 19 taken 2 times.
✗ Branch 18 → 229 not taken.
2 CheckAndConvertParams(local_config, env);
1148
2/2
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 28 taken 1 time.
2 if (use_lut) {
1149
2/2
✓ Branch 27 → 21 taken 3 times.
✓ Branch 27 → 28 taken 1 time.
4 for (int plane = 0; plane < (int)number_of_maps; plane++) {
1150 // recalculate plane LUT only if changed
1151
1/2
✓ Branch 21 → 22 taken 3 times.
✗ Branch 21 → 26 not taken.
3 if (local_config.rgba[plane].changed)
1152 {
1153 3 size_t local_lut_size = static_cast<size_t>(pixelsize) * real_lookup_size;
1154
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 3 times.
3 if (dither) local_lut_size *= 256;
1155
1/2
✓ Branch 24 → 25 taken 3 times.
✗ Branch 24 → 229 not taken.
3 maps_local[plane] = new BYTE[local_lut_size];
1156 3 maps_live[plane] = maps_local[plane]; // use our new local lut
1157
1/2
✓ Branch 25 → 26 taken 3 times.
✗ Branch 25 → 229 not taken.
3 rgbadjust_create_lut(maps_live[plane], plane, local_config);
1158 }
1159 }
1160 }
1161 }
1162
1163
2/2
✓ Branch 28 → 29 taken 1 time.
✓ Branch 28 → 55 taken 13 times.
14 if (dither) {
1164
2/4
✓ Branch 29 → 30 taken 1 time.
✗ Branch 29 → 229 not taken.
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 1 time.
1 if (vi.IsRGB32())
1165 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);
1166
2/4
✓ Branch 32 → 33 taken 1 time.
✗ Branch 32 → 229 not taken.
✓ Branch 33 → 34 taken 1 time.
✗ Branch 33 → 35 not taken.
1 else if(vi.IsRGB24())
1167 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);
1168 else if(vi.IsRGB64())
1169 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);
1170 else if(vi.IsRGB48())
1171 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);
1172 else {
1173 // Planar RGB
1174 bool hasAlpha = vi.IsPlanarRGBA();
1175 BYTE *p_g = p;
1176 BYTE *p_b = frame->GetWritePtr(PLANAR_B);
1177 BYTE *p_r = frame->GetWritePtr(PLANAR_R);
1178 BYTE *p_a = frame->GetWritePtr(PLANAR_A);
1179 // no float support
1180 if(pixelsize==1) {
1181 if(hasAlpha)
1182 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);
1183 else
1184 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);
1185 }
1186 else {
1187 if(hasAlpha)
1188 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);
1189 else
1190 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);
1191 }
1192 }
1193 }
1194 else {
1195 // no dither
1196
3/4
✓ Branch 55 → 56 taken 13 times.
✗ Branch 55 → 229 not taken.
✓ Branch 56 → 57 taken 1 time.
✓ Branch 56 → 58 taken 12 times.
13 if (vi.IsRGB32())
1197 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);
1198
3/4
✓ Branch 58 → 59 taken 12 times.
✗ Branch 58 → 229 not taken.
✓ Branch 59 → 60 taken 5 times.
✓ Branch 59 → 61 taken 7 times.
12 else if(vi.IsRGB24())
1199 5 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);
1200
3/4
✓ Branch 61 → 62 taken 7 times.
✗ Branch 61 → 229 not taken.
✓ Branch 62 → 63 taken 1 time.
✓ Branch 62 → 64 taken 6 times.
7 else if(vi.IsRGB64())
1201 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);
1202
2/4
✓ Branch 64 → 65 taken 6 times.
✗ Branch 64 → 229 not taken.
✗ Branch 65 → 66 not taken.
✓ Branch 65 → 67 taken 6 times.
6 else if(vi.IsRGB48())
1203 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);
1204 else {
1205 // Planar RGB
1206
1/2
✓ Branch 67 → 68 taken 6 times.
✗ Branch 67 → 229 not taken.
6 bool hasAlpha = vi.IsPlanarRGBA();
1207 6 BYTE *p_g = p;
1208
1/2
✓ Branch 69 → 70 taken 6 times.
✗ Branch 69 → 229 not taken.
6 BYTE *p_b = frame->GetWritePtr(PLANAR_B);
1209
1/2
✓ Branch 71 → 72 taken 6 times.
✗ Branch 71 → 229 not taken.
6 BYTE *p_r = frame->GetWritePtr(PLANAR_R);
1210
1/2
✓ Branch 73 → 74 taken 6 times.
✗ Branch 73 → 229 not taken.
6 BYTE *p_a = frame->GetWritePtr(PLANAR_A);
1211 // no float support
1212
1/2
✗ Branch 74 → 75 not taken.
✓ Branch 74 → 78 taken 6 times.
6 if(pixelsize==1) {
1213 if(hasAlpha)
1214 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);
1215 else
1216 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);
1217 }
1218
2/2
✓ Branch 78 → 79 taken 1 time.
✓ Branch 78 → 82 taken 5 times.
6 else if(pixelsize==2) {
1219
1/2
✗ Branch 79 → 80 not taken.
✓ Branch 79 → 81 taken 1 time.
1 if(hasAlpha)
1220 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);
1221 else
1222 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);
1223 }
1224 else {
1225 // 32 bit float, no dither
1226 5 const int planesRGB_RgbaOrder[4] = { PLANAR_R, PLANAR_G, PLANAR_B, PLANAR_A };
1227 5 const int *planes = planesRGB_RgbaOrder;
1228
1229
4/4
✓ Branch 95 → 96 taken 20 times.
✓ Branch 95 → 97 taken 4 times.
✓ Branch 98 → 83 taken 19 times.
✓ Branch 98 → 99 taken 5 times.
24 for (int cplane = 0; cplane < (hasAlpha ? 4 : 3); cplane++) {
1230 19 RGBAdjustPlaneConfig x = local_config.rgba[cplane];
1231 19 const double scale = x.scale;
1232 19 const double bias = x.bias;
1233 19 const double gamma = 1 / x.gamma;
1234 19 int plane = planes[cplane];
1235
1/2
✓ Branch 84 → 85 taken 19 times.
✗ Branch 84 → 225 not taken.
19 float* dstp = reinterpret_cast<float *>(frame->GetWritePtr(plane));
1236
1/2
✓ Branch 86 → 87 taken 19 times.
✗ Branch 86 → 225 not taken.
19 int pitch = frame->GetPitch(plane) / sizeof(float);
1237
2/2
✓ Branch 93 → 88 taken 408 times.
✓ Branch 93 → 94 taken 19 times.
427 for (int y = 0; y < h; y++) {
1238
2/2
✓ Branch 91 → 89 taken 115440 times.
✓ Branch 91 → 92 taken 408 times.
115848 for (int x = 0; x < w; x++) {
1239
1/2
✓ Branch 89 → 90 taken 115440 times.
✗ Branch 89 → 225 not taken.
115440 dstp[x] = RGBAdjust_processPixel(dstp[x], bias, scale, gamma);
1240 }
1241 408 dstp += pitch;
1242 }
1243 }
1244 }
1245 }
1246 }
1247
1248
2/2
✓ Branch 100 → 101 taken 9 times.
✓ Branch 100 → 107 taken 5 times.
14 if (use_lut) {
1249 // no need to check conditional here, because local LUTs are allocated only if the
1250 // conditional changed something.
1251
2/2
✓ Branch 106 → 102 taken 36 times.
✓ Branch 106 → 107 taken 9 times.
45 for(int i = 0; i<4; i++)
1252
3/4
✓ Branch 102 → 103 taken 3 times.
✓ Branch 102 → 105 taken 33 times.
✓ Branch 103 → 104 taken 3 times.
✗ Branch 103 → 105 not taken.
36 if (maps_local[i]) delete[] maps_local[i];
1253 }
1254
1255
2/2
✓ Branch 107 → 108 taken 2 times.
✓ Branch 107 → 223 taken 12 times.
14 if (analyze) {
1256
1/2
✓ Branch 109 → 110 taken 2 times.
✗ Branch 109 → 229 not taken.
2 const int w = frame->GetRowSize() / pixelsize;
1257
1/2
✓ Branch 111 → 112 taken 2 times.
✗ Branch 111 → 229 not taken.
2 const int h = frame->GetHeight();
1258
1259
2/2
✓ Branch 112 → 113 taken 1 time.
✓ Branch 112 → 114 taken 1 time.
2 const int analyze_lookup_size = pixelsize == 4 ? 1 << 16 : 1 << bits_per_pixel; // 32 bit float is quantized to 16 bits
1260 2 const int max_pixel_value_analyze = analyze_lookup_size - 1;
1261
1262 // allocate 3x bufsize for R. G and B will share it
1263
1/2
✓ Branch 115 → 116 taken 2 times.
✗ Branch 115 → 229 not taken.
2 auto accum_r = static_cast<uint32_t*>(env->Allocate(analyze_lookup_size * sizeof(uint32_t) * 3, 16, AVS_NORMAL_ALLOC));
1264 2 auto accum_g = accum_r + analyze_lookup_size;
1265 2 auto accum_b = accum_g + analyze_lookup_size;
1266
1/2
✗ Branch 116 → 117 not taken.
✓ Branch 116 → 118 taken 2 times.
2 if (!accum_r)
1267 env->ThrowError("RGBAdjust: Could not reserve memory.");
1268
1269
2/2
✓ Branch 120 → 119 taken 65792 times.
✓ Branch 120 → 121 taken 2 times.
65794 for (int i = 0; i < analyze_lookup_size; i++) {
1270 65792 accum_r[i] = 0;
1271 65792 accum_g[i] = 0;
1272 65792 accum_b[i] = 0;
1273 }
1274
1275 2 const int pixels = vi.width * vi.height;
1276
1277
2/2
✓ Branch 121 → 122 taken 1 time.
✓ Branch 121 → 153 taken 1 time.
2 if (bits_per_pixel == 32) {
1278 RGBStats rgbplanedata;
1279
1/2
✓ Branch 123 → 124 taken 1 time.
✗ Branch 123 → 227 not taken.
1 const BYTE* p_g = frame->GetReadPtr(PLANAR_G);;
1280
1/2
✓ Branch 125 → 126 taken 1 time.
✗ Branch 125 → 227 not taken.
1 const BYTE* p_b = frame->GetReadPtr(PLANAR_B);
1281
1/2
✓ Branch 127 → 128 taken 1 time.
✗ Branch 127 → 227 not taken.
1 const BYTE* p_r = frame->GetReadPtr(PLANAR_R);
1282
1/2
✓ Branch 128 → 129 taken 1 time.
✗ Branch 128 → 227 not taken.
1 fill_accum_rgb_planar_float_c(p_r, p_g, p_b, pitch, accum_r, accum_g, accum_b, w, h, rgbplanedata);
1283
1284 1 double avg_r = rgbplanedata.data[0].sum / pixels;
1285 1 double avg_g = rgbplanedata.data[1].sum / pixels;
1286 1 double avg_b = rgbplanedata.data[2].sum / pixels;
1287
1288 1 int Amin_r = 0, Amin_g = 0, Amin_b = 0;
1289 1 int Amax_r = 0, Amax_g = 0, Amax_b = 0;
1290 1 bool Ahit_minr = false, Ahit_ming = false, Ahit_minb = false;
1291 1 bool Ahit_maxr = false, Ahit_maxg = false, Ahit_maxb = false;
1292 1 int At_256 = (pixels + 128) / 256; // When 1/256th of all pixels have been reached, trigger "Loose min/max"
1293
1294 1 double st_r = 0, st_g = 0, st_b = 0;
1295
1296
2/2
✓ Branch 149 → 130 taken 65536 times.
✓ Branch 149 → 150 taken 1 time.
65537 for (int i = 0; i < analyze_lookup_size; i++) {
1297 65536 double i_float = i / 65535.0;
1298 65536 st_r += accum_r[i] * (i_float - avg_r) * (i_float - avg_r);
1299 65536 st_g += accum_g[i] * (i_float - avg_g) * (i_float - avg_g);
1300 65536 st_b += accum_b[i] * (i_float - avg_b) * (i_float - avg_b);
1301
1302 // loose min
1303
4/4
✓ Branch 130 → 131 taken 257 times.
✓ Branch 130 → 133 taken 65279 times.
✓ Branch 131 → 132 taken 1 time.
✓ Branch 131 → 133 taken 256 times.
65536 if (!Ahit_minr) { Amin_r += accum_r[i]; if (Amin_r > At_256) { Ahit_minr = true; Amin_r = i; } }
1304
4/4
✓ Branch 133 → 134 taken 257 times.
✓ Branch 133 → 136 taken 65279 times.
✓ Branch 134 → 135 taken 1 time.
✓ Branch 134 → 136 taken 256 times.
65536 if (!Ahit_ming) { Amin_g += accum_g[i]; if (Amin_g > At_256) { Ahit_ming = true; Amin_g = i; } }
1305
4/4
✓ Branch 136 → 137 taken 257 times.
✓ Branch 136 → 139 taken 65279 times.
✓ Branch 137 → 138 taken 1 time.
✓ Branch 137 → 139 taken 256 times.
65536 if (!Ahit_minb) { Amin_b += accum_b[i]; if (Amin_b > At_256) { Ahit_minb = true; Amin_b = i; } }
1306 // loose max
1307
4/4
✓ Branch 139 → 140 taken 257 times.
✓ Branch 139 → 142 taken 65279 times.
✓ Branch 140 → 141 taken 1 time.
✓ Branch 140 → 142 taken 256 times.
65536 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; } }
1308
4/4
✓ Branch 142 → 143 taken 257 times.
✓ Branch 142 → 145 taken 65279 times.
✓ Branch 143 → 144 taken 1 time.
✓ Branch 143 → 145 taken 256 times.
65536 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; } }
1309
4/4
✓ Branch 145 → 146 taken 257 times.
✓ Branch 145 → 148 taken 65279 times.
✓ Branch 146 → 147 taken 1 time.
✓ Branch 146 → 148 taken 256 times.
65536 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; } }
1310 }
1311
1312 1 auto Fst_r = sqrt(st_r / pixels);
1313 1 auto Fst_g = sqrt(st_g / pixels);
1314 1 auto Fst_b = sqrt(st_b / pixels);
1315
1316 char text[512];
1317 1 const bool StatsAsInteger16 = false;
1318 if(StatsAsInteger16)
1319 sprintf(text,
1320 "At 16 bits. Frame: %-8u ( Red / Green / Blue )\n"
1321 " Average: ( %7.2f / %7.2f / %7.2f )\n"
1322 "Standard Deviation: ( %7.2f / %7.2f / %7.2f )\n"
1323 " Minimum: ( %7.2f / %7.2f / %7.2f )\n"
1324 " Maximum: ( %7.2f / %7.2f / %7.2f )\n"
1325 " Loose Minimum: ( %5d / %5d / %5d )\n"
1326 " Loose Maximum: ( %5d / %5d / %5d )\n"
1327 ,
1328 (unsigned int)n,
1329 avg_r * 65535, avg_g * 65535, avg_b * 65535,
1330 Fst_r * 65535, Fst_g * 65535, Fst_b * 65535,
1331 rgbplanedata.data[0].real_min * 65535, rgbplanedata.data[1].real_min * 65535, rgbplanedata.data[2].real_min * 65535,
1332 rgbplanedata.data[0].real_max * 65535, rgbplanedata.data[1].real_max * 65535, rgbplanedata.data[2].real_max * 65535,
1333 Amin_r, Amin_g, Amin_b,
1334 Amax_r, Amax_g, Amax_b
1335 );
1336 else // stats as Float
1337 1 sprintf(text,
1338 " Frame: %-8u ( Red / Green / Blue )\n"
1339 " Average: ( %7.5f / %7.5f / %7.5f )\n"
1340 "Standard Deviation: ( %7.5f / %7.5f / %7.5f )\n"
1341 " Minimum: ( %7.5f / %7.5f / %7.5f )\n"
1342 " Maximum: ( %7.5f / %7.5f / %7.5f )\n"
1343 " Loose Minimum: ( %7.5f / %7.5f / %7.5f )\n"
1344 " Loose Maximum: ( %7.5f / %7.5f / %7.5f )\n"
1345 ,
1346 (unsigned int)n,
1347 avg_r, avg_g, avg_b,
1348 Fst_r, Fst_g, Fst_b,
1349 1 rgbplanedata.data[0].real_min, rgbplanedata.data[1].real_min, rgbplanedata.data[2].real_min,
1350 1 rgbplanedata.data[0].real_max, rgbplanedata.data[1].real_max, rgbplanedata.data[2].real_max,
1351 Amin_r / 65535.0, Amin_g / 65535.0, Amin_b / 65535.0,
1352 Amax_r / 65535.0, Amax_g / 65535.0, Amax_b / 65535.0
1353 );
1354
1/2
✓ Branch 151 → 152 taken 1 time.
✗ Branch 151 → 227 not taken.
1 env->ApplyMessage(&frame, vi, text, vi.width / 4, 0xa0a0a0, 0, 0);
1355 }
1356 else {
1357
1358
5/10
✓ Branch 153 → 154 taken 1 time.
✗ Branch 153 → 228 not taken.
✓ Branch 154 → 155 taken 1 time.
✗ Branch 154 → 157 not taken.
✓ Branch 155 → 156 taken 1 time.
✗ Branch 155 → 228 not taken.
✗ Branch 156 → 157 not taken.
✓ Branch 156 → 158 taken 1 time.
✗ Branch 159 → 160 not taken.
✓ Branch 159 → 170 taken 1 time.
1 if (vi.IsPlanarRGB() || vi.IsPlanarRGBA())
1359 {
1360 const BYTE* p_g = frame->GetReadPtr(PLANAR_G);;
1361 const BYTE* p_b = frame->GetReadPtr(PLANAR_B);
1362 const BYTE* p_r = frame->GetReadPtr(PLANAR_R);
1363 if (bits_per_pixel == 8)
1364 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);
1365 else if (bits_per_pixel <= 16)
1366 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);
1367 else // 32 bit float
1368 ;// handled in other branch;
1369 }
1370 else {
1371 // packed RGB
1372
1/2
✓ Branch 171 → 172 taken 1 time.
✗ Branch 171 → 228 not taken.
1 const BYTE* srcp = frame->GetReadPtr();
1373
2/8
✓ Branch 172 → 173 taken 1 time.
✗ Branch 172 → 228 not taken.
✗ Branch 173 → 174 not taken.
✓ Branch 173 → 176 taken 1 time.
✗ Branch 174 → 175 not taken.
✗ Branch 174 → 228 not taken.
✗ Branch 175 → 176 not taken.
✗ Branch 175 → 177 not taken.
1 const int pixel_step = vi.IsRGB24() || vi.IsRGB48() ? 3 : 4;
1374
1375
1/2
✓ Branch 178 → 179 taken 1 time.
✗ Branch 178 → 180 not taken.
1 if (pixelsize == 1)
1376 1 fill_accum_rgb_packed_c<uint8_t>(srcp, pitch, accum_r, accum_g, accum_b, w, h, pixel_step);
1377 else
1378 fill_accum_rgb_packed_c<uint16_t>(srcp, pitch, accum_r, accum_g, accum_b, w, h, pixel_step);
1379 }
1380
1381 1 double avg_r = 0, avg_g = 0, avg_b = 0;
1382 1 double st_r = 0, st_g = 0, st_b = 0;
1383 1 int min_r = 0, min_g = 0, min_b = 0;
1384 1 int max_r = 0, max_g = 0, max_b = 0;
1385 1 bool hit_r = false, hit_g = false, hit_b = false;
1386 1 int Amin_r = 0, Amin_g = 0, Amin_b = 0;
1387 1 int Amax_r = 0, Amax_g = 0, Amax_b = 0;
1388 1 bool Ahit_minr = false, Ahit_ming = false, Ahit_minb = false;
1389 1 bool Ahit_maxr = false, Ahit_maxg = false, Ahit_maxb = false;
1390 1 int At_256 = (pixels + 128) / 256; // When 1/256th of all pixels have been reached, trigger "Loose min/max"
1391
1392
2/2
✓ Branch 213 → 182 taken 256 times.
✓ Branch 213 → 214 taken 1 time.
257 for (int i = 0; i < analyze_lookup_size; i++) {
1393 256 avg_r += (double)accum_r[i] * i;
1394 256 avg_g += (double)accum_g[i] * i;
1395 256 avg_b += (double)accum_b[i] * i;
1396
1397
1/2
✓ Branch 182 → 183 taken 256 times.
✗ Branch 182 → 184 not taken.
256 if (accum_r[i] != 0) { max_r = i; hit_r = true; }
1398 else { if (!hit_r) min_r = i + 1; }
1399
1/2
✓ Branch 186 → 187 taken 256 times.
✗ Branch 186 → 188 not taken.
256 if (accum_g[i] != 0) { max_g = i; hit_g = true; }
1400 else { if (!hit_g) min_g = i + 1; }
1401
1/2
✓ Branch 190 → 191 taken 256 times.
✗ Branch 190 → 192 not taken.
256 if (accum_b[i] != 0) { max_b = i; hit_b = true; }
1402 else { if (!hit_b) min_b = i + 1; }
1403
1404
4/4
✓ Branch 194 → 195 taken 2 times.
✓ Branch 194 → 197 taken 254 times.
✓ Branch 195 → 196 taken 1 time.
✓ Branch 195 → 197 taken 1 time.
256 if (!Ahit_minr) { Amin_r += accum_r[i]; if (Amin_r > At_256) { Ahit_minr = true; Amin_r = i; } }
1405
4/4
✓ Branch 197 → 198 taken 2 times.
✓ Branch 197 → 200 taken 254 times.
✓ Branch 198 → 199 taken 1 time.
✓ Branch 198 → 200 taken 1 time.
256 if (!Ahit_ming) { Amin_g += accum_g[i]; if (Amin_g > At_256) { Ahit_ming = true; Amin_g = i; } }
1406
4/4
✓ Branch 200 → 201 taken 2 times.
✓ Branch 200 → 203 taken 254 times.
✓ Branch 201 → 202 taken 1 time.
✓ Branch 201 → 203 taken 1 time.
256 if (!Ahit_minb) { Amin_b += accum_b[i]; if (Amin_b > At_256) { Ahit_minb = true; Amin_b = i; } }
1407
1408
4/4
✓ Branch 203 → 204 taken 2 times.
✓ Branch 203 → 206 taken 254 times.
✓ Branch 204 → 205 taken 1 time.
✓ Branch 204 → 206 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; } }
1409
4/4
✓ Branch 206 → 207 taken 2 times.
✓ Branch 206 → 209 taken 254 times.
✓ Branch 207 → 208 taken 1 time.
✓ Branch 207 → 209 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; } }
1410
4/4
✓ Branch 209 → 210 taken 2 times.
✓ Branch 209 → 212 taken 254 times.
✓ Branch 210 → 211 taken 1 time.
✓ Branch 210 → 212 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; } }
1411 }
1412
1413 1 float Favg_r = (float)(avg_r / pixels);
1414 1 float Favg_g = (float)(avg_g / pixels);
1415 1 float Favg_b = (float)(avg_b / pixels);
1416
1417
2/2
✓ Branch 216 → 215 taken 256 times.
✓ Branch 216 → 217 taken 1 time.
257 for (int i = 0; i < analyze_lookup_size; i++) {
1418 256 st_r += (float)accum_r[i] * (float(i - Favg_r) * (i - Favg_r));
1419 256 st_g += (float)accum_g[i] * (float(i - Favg_g) * (i - Favg_g));
1420 256 st_b += (float)accum_b[i] * (float(i - Favg_b) * (i - Favg_b));
1421 }
1422
1423 1 float Fst_r = (float)sqrt(st_r / pixels);
1424 1 float Fst_g = (float)sqrt(st_g / pixels);
1425 1 float Fst_b = (float)sqrt(st_b / pixels);
1426
1427 char text[512];
1428
1/2
✓ Branch 217 → 218 taken 1 time.
✗ Branch 217 → 219 not taken.
1 if (bits_per_pixel == 8)
1429 1 sprintf(text,
1430 " Frame: %-8u ( Red / Green / Blue )\n"
1431 " Average: ( %5.2f / %5.2f / %5.2f )\n"
1432 "Standard Deviation: ( %5.2f / %5.2f / %5.2f )\n"
1433 " Minimum: ( %3d / %3d / %3d )\n"
1434 " Maximum: ( %3d / %3d / %3d )\n"
1435 " Loose Minimum: ( %3d / %3d / %3d )\n"
1436 " Loose Maximum: ( %3d / %3d / %3d )\n"
1437 ,
1438 (unsigned int)n,
1439 Favg_r, Favg_g, Favg_b,
1440 Fst_r, Fst_g, Fst_b,
1441 min_r, min_g, min_b,
1442 max_r, max_g, max_b,
1443 Amin_r, Amin_g, Amin_b,
1444 Amax_r, Amax_g, Amax_b
1445 );
1446 else // if (bits_per_pixel <= 16)
1447 sprintf(text,
1448 " Frame: %-8u ( Red / Green / Blue )\n"
1449 " Average: ( %7.2f / %7.2f / %7.2f )\n"
1450 "Standard Deviation: ( %7.2f / %7.2f / %7.2f )\n"
1451 " Minimum: ( %5d / %5d / %5d )\n"
1452 " Maximum: ( %5d / %5d / %5d )\n"
1453 " Loose Minimum: ( %5d / %5d / %5d )\n"
1454 " Loose Maximum: ( %5d / %5d / %5d )\n"
1455 ,
1456 (unsigned int)n,
1457 Favg_r, Favg_g, Favg_b,
1458 Fst_r, Fst_g, Fst_b,
1459 min_r, min_g, min_b,
1460 max_r, max_g, max_b,
1461 Amin_r, Amin_g, Amin_b,
1462 Amax_r, Amax_g, Amax_b
1463 );
1464
1/2
✓ Branch 220 → 221 taken 1 time.
✗ Branch 220 → 228 not taken.
1 env->ApplyMessage(&frame, vi, text, vi.width / 4, 0xa0a0a0, 0, 0);
1465 }
1466
1/2
✓ Branch 222 → 223 taken 2 times.
✗ Branch 222 → 229 not taken.
2 env->Free(accum_r);
1467 }
1468 14 return frame;
1469 }
1470
1471
1472 AVSValue __cdecl RGBAdjust::Create(AVSValue args, void*, IScriptEnvironment* env)
1473 {
1474 return new RGBAdjust(args[ 0].AsClip(),
1475 args[ 1].AsDblDef(1.0), args[ 2].AsDblDef(1.0), args[ 3].AsDblDef(1.0), args[ 4].AsDblDef(1.0),
1476 args[ 5].AsDblDef(0.0), args[ 6].AsDblDef(0.0), args[ 7].AsDblDef(0.0), args[ 8].AsDblDef(0.0),
1477 args[ 9].AsDblDef(1.0), args[10].AsDblDef(1.0), args[11].AsDblDef(1.0), args[12].AsDblDef(1.0),
1478 args[13].AsBool(false), args[14].AsBool(false), args[15].AsBool(false), args[16].AsString(""), env );
1479 }
1480
1481
1482
1483 /* helper function for Tweak and MaskHS filters */
1484 131108 static bool ProcessPixel(double X, double Y, double startHue, double endHue,
1485 double maxSat, double minSat, double p, int &iSat)
1486 {
1487 // a hue analog
1488 131108 double T = atan2(X, Y) * 180.0 / PI;
1489
2/2
✓ Branch 2 → 3 taken 65546 times.
✓ Branch 2 → 4 taken 65562 times.
131108 if (T < 0.0) T += 360.0;
1490
1491 // startHue <= hue <= endHue
1492
2/2
✓ Branch 4 → 5 taken 8 times.
✓ Branch 4 → 8 taken 131100 times.
131108 if (startHue < endHue) {
1493
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;
1494 }
1495 else {
1496
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;
1497 }
1498
1499 32986 const double W = X*X + Y*Y;
1500
1501 // In Range, full adjust but no need to interpolate
1502
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;
1503
1504 // p == 0 (no interpolation) needed for MaskHS
1505
1/2
✓ Branch 14 → 15 taken 17636 times.
✗ Branch 14 → 16 not taken.
17636 if (p == 0.0) return false;
1506
1507 // Interpolation range is +/-p for p>0
1508 // 180 is not in degrees!
1509 // its sqrt(127^2 + 127^2): max overshoot for 8 bits; U and V is 0 +/- 127
1510 const double max = min(maxSat + p, 180.0);
1511 const double min = ::max(minSat - p, 0.0);
1512
1513 // Outside of [min-p, max+p] no adjustment
1514 // minSat-p <= (U^2 + V^2) <= maxSat+p
1515 if (W <= min*min || max*max <= W) return false; // don't adjust
1516
1517 // Interpolate saturation value
1518 const double holdSat = W < 180.0*180.0 ? sqrt(W) : 180.0;
1519
1520 if (holdSat < minSat) { // within p of lower range
1521 iSat += (int)((512 - iSat) * (minSat - holdSat) / p);
1522 }
1523 else { // within p of upper range
1524 iSat += (int)((512 - iSat) * (holdSat - maxSat) / p);
1525 }
1526
1527 return true;
1528 }
1529
1530 // for float
1531 14 static bool ProcessPixelUnscaled(double X, double Y, double startHue, double endHue,
1532 double maxSat, double minSat, double p, double &dSat)
1533 {
1534 // a hue analog
1535 14 double T = atan2(X, Y) * 180.0 / PI;
1536
2/2
✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 4 taken 10 times.
14 if (T < 0.0) T += 360.0;
1537
1538 // startHue <= hue <= endHue
1539
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 8 taken 14 times.
14 if (startHue < endHue) {
1540 if (T > endHue || T < startHue) return false;
1541 }
1542 else {
1543
4/4
✓ Branch 8 → 9 taken 12 times.
✓ Branch 8 → 11 taken 2 times.
✓ Branch 9 → 10 taken 4 times.
✓ Branch 9 → 11 taken 8 times.
14 if (T<startHue && T>endHue) return false;
1544 }
1545
1546 10 const double W = X*X + Y*Y;
1547
1548 // In Range, full adjust but no need to interpolate
1549
4/4
✓ Branch 11 → 12 taken 8 times.
✓ Branch 11 → 14 taken 2 times.
✓ Branch 12 → 13 taken 6 times.
✓ Branch 12 → 14 taken 2 times.
10 if (minSat*minSat <= W && W <= maxSat*maxSat) return true;
1550
1551 // p == 0 (no interpolation) needed for MaskHS
1552
1/2
✓ Branch 14 → 15 taken 4 times.
✗ Branch 14 → 16 not taken.
4 if (p == 0.0) return false;
1553
1554 // Interpolation range is +/-p for p>0
1555 const double max = min(maxSat + p, 180.0);
1556 const double min = ::max(minSat - p, 0.0);
1557
1558 // Outside of [min-p, max+p] no adjustment
1559 // minSat-p <= (U^2 + V^2) <= maxSat+p
1560 if (W <= min*min || max*max <= W) return false; // don't adjust
1561
1562 // Interpolate saturation value
1563 const double holdSat = W < 180.0*180.0 ? sqrt(W) : 180.0;
1564
1565 if (holdSat < minSat) { // within p of lower range
1566 dSat += ((1 - dSat) * (minSat - holdSat) / p);
1567 }
1568 else { // within p of upper range
1569 dSat += ((1 - dSat) * (holdSat - maxSat) / p);
1570 }
1571
1572 return true;
1573 }
1574
1575
1576 /**********************
1577 ****** Tweak *****
1578 **********************/
1579 template<typename pixel_t, bool bpp10_14, bool dither>
1580 10 void Tweak::tweak_calc_luma(BYTE *srcp, int src_pitch, float minY, float maxY, int width, int height)
1581 {
1582 10 float ditherval = 0.0f;
1583
12/16
void Tweak::tweak_calc_luma<float, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 21 → 3 taken 4 times.
✓ Branch 21 → 22 taken 2 times.
void Tweak::tweak_calc_luma<float, false, true>(unsigned char*, int, float, float, int, int):
✓ Branch 21 → 3 taken 4 times.
✓ Branch 21 → 22 taken 2 times.
void Tweak::tweak_calc_luma<unsigned char, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 21 → 3 taken 4 times.
✓ Branch 21 → 22 taken 2 times.
void Tweak::tweak_calc_luma<unsigned char, false, true>(unsigned char*, int, float, float, int, int):
✗ Branch 21 → 3 not taken.
✗ Branch 21 → 22 not taken.
void Tweak::tweak_calc_luma<unsigned short, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 21 → 3 taken 12 times.
✓ Branch 21 → 22 taken 2 times.
void Tweak::tweak_calc_luma<unsigned short, false, true>(unsigned char*, int, float, float, int, int):
✓ Branch 21 → 3 taken 6 times.
✓ Branch 21 → 22 taken 1 time.
void Tweak::tweak_calc_luma<unsigned short, true, false>(unsigned char*, int, float, float, int, int):
✓ Branch 17 → 3 taken 2 times.
✓ Branch 17 → 18 taken 1 time.
void Tweak::tweak_calc_luma<unsigned short, true, true>(unsigned char*, int, float, float, int, int):
✗ Branch 17 → 3 not taken.
✗ Branch 17 → 18 not taken.
42 for (int y = 0; y < height; ++y) {
1584 32 const int _y = (y << 4) & 0xf0;
1585
12/16
void Tweak::tweak_calc_luma<float, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 19 → 4 taken 24 times.
✓ Branch 19 → 20 taken 4 times.
void Tweak::tweak_calc_luma<float, false, true>(unsigned char*, int, float, float, int, int):
✓ Branch 19 → 4 taken 20 times.
✓ Branch 19 → 20 taken 4 times.
void Tweak::tweak_calc_luma<unsigned char, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 19 → 4 taken 32 times.
✓ Branch 19 → 20 taken 4 times.
void Tweak::tweak_calc_luma<unsigned char, false, true>(unsigned char*, int, float, float, int, int):
✗ Branch 19 → 4 not taken.
✗ Branch 19 → 20 not taken.
void Tweak::tweak_calc_luma<unsigned short, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 19 → 4 taken 96 times.
✓ Branch 19 → 20 taken 12 times.
void Tweak::tweak_calc_luma<unsigned short, false, true>(unsigned char*, int, float, float, int, int):
✓ Branch 19 → 4 taken 48 times.
✓ Branch 19 → 20 taken 6 times.
void Tweak::tweak_calc_luma<unsigned short, true, false>(unsigned char*, int, float, float, int, int):
✓ Branch 15 → 4 taken 14 times.
✓ Branch 15 → 16 taken 2 times.
void Tweak::tweak_calc_luma<unsigned short, true, true>(unsigned char*, int, float, float, int, int):
✗ Branch 15 → 4 not taken.
✗ Branch 15 → 16 not taken.
266 for (int x = 0; x < width; ++x) {
1586 if (dither)
1587 68 ditherval = (ditherMap[(x & 0x0f) | _y] * dither_strength + bias_dither_luma) / (float)scale_dither_luma; // 0x00..0xFF -> -0.7F .. + 0.7F (+/- maxrange/512)
1588 234 float y0 = reinterpret_cast<pixel_t *>(srcp)[x] - minY;
1589 if(bpp10_14)
1590 14 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
1591
5/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 24 times.
void Tweak::tweak_calc_luma<float, false, true>(unsigned char*, int, float, float, int, int):
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 20 times.
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.
220 else if(pixelsize == 2)
1592 144 y0 = minY + (y0 + ditherval)*(float)dcont + 256.0f*(float)dbright; // dbright parameter always 0..255. Scale to 0..255*4, 0.. 255*256
1593
3/12
void Tweak::tweak_calc_luma<float, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 7 → 8 taken 24 times.
✗ Branch 7 → 9 not taken.
void Tweak::tweak_calc_luma<float, false, true>(unsigned char*, int, float, float, int, int):
✓ Branch 7 → 8 taken 20 times.
✗ 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.
76 else if(pixelsize == 4)
1594 44 y0 = minY + (y0 + ditherval)*(float)dcont + (float)dbright / 256.0f; // dbright parameter always 0..255, scale it to 0..1
1595 else // pixelsize == 1
1596 32 y0 = minY + ((y0 + ditherval)*(float)dcont + 1.0f*(float)dbright); // dbright parameter always 0..255. Scale to 0..255*4, 0.. 255*256
1597
1598
4/4
void Tweak::tweak_calc_luma<float, false, false>(unsigned char*, int, float, float, int, int):
✓ Branch 10 → 11 taken 2 times.
✓ Branch 10 → 12 taken 22 times.
void Tweak::tweak_calc_luma<float, false, true>(unsigned char*, int, float, float, int, int):
✓ Branch 10 → 11 taken 4 times.
✓ Branch 10 → 12 taken 16 times.
278 reinterpret_cast<pixel_t *>(srcp)[x] = (pixel_t)clamp(y0, minY, maxY);
1599 /*
1600 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
1601 // coring, dither:
1602 // int y = int(((ii - 16 * 256)*_cont + _bright * 256 - 127.5) / 256 + 16.5); // 256 _cont & _bright param range
1603 // coring, no dither:
1604 // int y = int(((ii - 16)*_cont + _bright) + 16.5); // 256 _cont & _bright param range
1605 // no coring, dither:
1606 // int y = int((ii *_cont + _bright * 256 - 127.5) / 256 + 0.5 ); // 256 _cont & _bright param range
1607 // no coring, no dither:
1608 // int y = int((ii *_cont + _bright) + 0.5 ); // 256 _cont & _bright param range
1609 */
1610 }
1611 32 srcp += src_pitch;
1612 }
1613 10 }
1614
1615 13 Tweak::Tweak(PClip _child, double _hue, double _sat, double _bright, double _cont, bool _coring,
1616 double _startHue, double _endHue, double _maxSat, double _minSat, double p,
1617 13 bool _dither, bool _realcalc, double _dither_strength, IScriptEnvironment* env)
1618 13 : GenericVideoFilter(_child), coring(_coring),
1619 13 dither(_dither), realcalc(_realcalc),
1620 13 dhue(_hue), dsat(_sat), dbright(_bright), dcont(_cont), dstartHue(_startHue), dendHue(_endHue),
1621
2/4
✓ Branch 2 → 3 taken 13 times.
✗ Branch 2 → 272 not taken.
✓ Branch 3 → 4 taken 13 times.
✗ Branch 3 → 270 not taken.
13 dmaxSat(_maxSat), dminSat(_minSat), dinterp(p), dither_strength((float)_dither_strength)
1622 {
1623
2/4
✓ Branch 5 → 6 taken 13 times.
✗ Branch 5 → 275 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 13 times.
13 if (vi.IsRGB())
1624 env->ThrowError("Tweak: YUV data only (no RGB)");
1625
1626
1/2
✓ Branch 8 → 9 taken 13 times.
✗ Branch 8 → 275 not taken.
13 pixelsize = vi.ComponentSize();
1627
1/2
✓ Branch 9 → 10 taken 13 times.
✗ Branch 9 → 275 not taken.
13 bits_per_pixel = vi.BitsPerComponent();
1628 13 max_pixel_value = (1 << bits_per_pixel) - 1;
1629 13 lut_size = 1 << bits_per_pixel;
1630
2/2
✓ Branch 10 → 11 taken 4 times.
✓ Branch 10 → 12 taken 9 times.
13 int safe_luma_lookup_size = (pixelsize == 1) ? 256 : 65536; // avoids lut overflow in case of non-standard content of a 10 bit clip
1631
1632 13 get_limits(limits, bits_per_pixel); // tv range limits
1633
1634 13 scale_dither_luma = 1;
1635 13 divisor_dither_luma = 1;
1636 13 bias_dither_luma = 0.0;
1637
1638 13 scale_dither_chroma = 1;
1639 13 divisor_dither_chroma = 1;
1640 13 bias_dither_chroma = 0.0;
1641
1642
2/2
✓ Branch 14 → 15 taken 4 times.
✓ Branch 14 → 16 taken 9 times.
13 if (pixelsize == 4)
1643 4 dither_strength /= 65536.0f; // same dither range as for a 16 bit clip
1644 // 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
1645 // Otherwise dithering is always +/- 0.5 at all bit-depth
1646
1647
2/2
✓ Branch 16 → 17 taken 3 times.
✓ Branch 16 → 21 taken 10 times.
13 if (dither) {
1648 // lut scale settings
1649 3 scale_dither_luma = 256; // lower 256 is dither value
1650 3 divisor_dither_luma *= 256;
1651 3 bias_dither_luma = -(256.0f * dither_strength - 1) / 2;
1652 // original bias: -127.5 or -(256.0f * dither_strength - 1) / 2;
1653 // dither strength =1 = (1 << (8-8))
1654 // dither min: int( (0*1-127.5)/256+0.5) = -0.498046875 + 0.5 = 0,001953125
1655 // dither max: int( (255*1-127.5)/256+0.5) = 0,998046875
1656
1657 // 16 bit: 32767,5
1658 // dither strength =256 = (1 << (16-8))
1659 // dither min: int( (0*256-32767,5)/256+0.5) = -127,498046875
1660 // dither max: int( (255*256-32767,5)/256+0.5) = 127,501953125
1661
1662
1663 3 scale_dither_chroma = 16; // lower 16 is dither value
1664 3 divisor_dither_chroma *= 16;
1665
2/2
✓ Branch 17 → 18 taken 2 times.
✓ Branch 17 → 19 taken 1 time.
3 bias_dither_chroma = -(16.0f * dither_strength - (pixelsize==4 ? 1/256.0f : 1)) / 2; // -7.5
1666 }
1667
1668 // Flag to skip special processing if doing all pixels
1669 // If defaults, don't check for ranges, just do all
1670
5/8
✓ Branch 21 → 22 taken 11 times.
✓ Branch 21 → 26 taken 2 times.
✓ Branch 22 → 23 taken 11 times.
✗ Branch 22 → 26 not taken.
✓ Branch 23 → 24 taken 11 times.
✗ Branch 23 → 26 not taken.
✓ Branch 24 → 25 taken 11 times.
✗ Branch 24 → 26 not taken.
13 allPixels = (_startHue == 0.0 && _endHue == 360.0 && _maxSat == 150.0 && _minSat == 0.0);
1671
1672
3/4
✓ Branch 27 → 28 taken 13 times.
✗ Branch 27 → 275 not taken.
✓ Branch 28 → 29 taken 1 time.
✓ Branch 28 → 33 taken 12 times.
13 if (vi.NumComponents() == 1) {
1673
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))
1674 env->ThrowError("Tweak: bright and cont are the only options available for greyscale.");
1675 }
1676
1677
2/4
✓ Branch 33 → 34 taken 13 times.
✗ Branch 33 → 35 not taken.
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 36 taken 13 times.
13 if (_startHue < 0.0 || _startHue >= 360.0)
1678 env->ThrowError("Tweak: startHue must be greater than or equal to 0.0 and less than 360.0");
1679
1680
2/4
✓ Branch 36 → 37 taken 13 times.
✗ Branch 36 → 38 not taken.
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 13 times.
13 if (_endHue <= 0.0 || _endHue > 360.0)
1681 env->ThrowError("Tweak: endHue must be greater than 0.0 and less than or equal to 360.0");
1682
1683
1/2
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 13 times.
13 if (_minSat >= _maxSat)
1684 env->ThrowError("Tweak: MinSat must be less than MaxSat");
1685
1686
2/4
✓ Branch 41 → 42 taken 13 times.
✗ Branch 41 → 43 not taken.
✗ Branch 42 → 43 not taken.
✓ Branch 42 → 44 taken 13 times.
13 if (_minSat < 0.0 || _minSat >= 150.0)
1687 env->ThrowError("Tweak: minSat must be greater than or equal to 0 and less than 150.");
1688
1689
2/4
✓ Branch 44 → 45 taken 13 times.
✗ Branch 44 → 46 not taken.
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 13 times.
13 if (_maxSat <= 0.0 || _maxSat > 150.0)
1690 env->ThrowError("Tweak: maxSat must be greater than 0 and less than or equal to 150.");
1691
1692
2/4
✓ Branch 47 → 48 taken 13 times.
✗ Branch 47 → 49 not taken.
✗ Branch 48 → 49 not taken.
✓ Branch 48 → 50 taken 13 times.
13 if (p>=150.0 || p<0.0)
1693 env->ThrowError("Tweak: Interp must be greater than or equal to 0 and less than 150.");
1694
1695 13 Sat = (int) (_sat * 512); // 9 bits extra precision
1696 13 Cont = (int) (_cont * 512);
1697 13 Bright = (int) _bright;
1698
1699 13 const double Hue = (_hue * PI) / 180.0;
1700 13 const double SIN = sin(Hue);
1701 13 const double COS = cos(Hue);
1702
1703 13 Sin = (int) (SIN * 4096 + 0.5);
1704 13 Cos = (int) (COS * 4096 + 0.5);
1705
1706 13 realcalc_luma = realcalc; // from parameter
1707 13 realcalc_chroma = realcalc;
1708
6/8
✓ Branch 50 → 51 taken 13 times.
✗ Branch 50 → 275 not taken.
✓ Branch 51 → 52 taken 13 times.
✗ Branch 51 → 54 not taken.
✓ Branch 52 → 53 taken 7 times.
✓ Branch 52 → 54 taken 6 times.
✓ Branch 55 → 56 taken 7 times.
✓ Branch 55 → 57 taken 6 times.
13 if (vi.IsPlanar() && (bits_per_pixel > 10))
1709 7 realcalc_chroma = true;
1710
6/8
✓ Branch 57 → 58 taken 13 times.
✗ Branch 57 → 275 not taken.
✓ Branch 58 → 59 taken 13 times.
✗ Branch 58 → 61 not taken.
✓ Branch 59 → 60 taken 4 times.
✓ Branch 59 → 61 taken 9 times.
✓ Branch 62 → 63 taken 4 times.
✓ Branch 62 → 64 taken 9 times.
13 if (vi.IsPlanar() && (bits_per_pixel == 32))
1711 4 realcalc_luma = true;
1712 // 8/10bit: chroma lut OK. 12+ bits: force no lookup tables.
1713 // 8-16bit: luma lut OK. float: force no lookup tables.
1714
1715 // fill brightness/constrast lookup tables
1716
6/8
✓ Branch 64 → 65 taken 10 times.
✓ Branch 64 → 67 taken 3 times.
✓ Branch 65 → 66 taken 10 times.
✗ Branch 65 → 275 not taken.
✗ Branch 66 → 67 not taken.
✓ Branch 66 → 68 taken 10 times.
✓ Branch 69 → 70 taken 3 times.
✓ Branch 69 → 117 taken 10 times.
13 if(!(realcalc_luma && vi.IsPlanar()))
1717 {
1718 3 size_t map_size = pixelsize * safe_luma_lookup_size * scale_dither_luma;
1719 // for 10-16 bit with dither: 2 * 65536 * 256 = 33 MByte
1720 // w/o dither: 2 * 65536 = 128 KByte
1721
1/2
✓ Branch 70 → 71 taken 3 times.
✗ Branch 70 → 275 not taken.
3 map = static_cast<uint8_t*>(env->Allocate(map_size, 8, AVS_NORMAL_ALLOC));
1722
1/2
✗ Branch 71 → 72 not taken.
✓ Branch 71 → 73 taken 3 times.
3 if (!map)
1723 env->ThrowError("Tweak: Could not reserve memory.");
1724
1/2
✓ Branch 73 → 74 taken 3 times.
✗ Branch 73 → 275 not taken.
3 env->AtExit(free_buffer, map);
1725
1726
3/4
✓ Branch 74 → 75 taken 1 time.
✓ Branch 74 → 86 taken 2 times.
✓ Branch 75 → 76 taken 1 time.
✗ Branch 75 → 86 not taken.
3 if(bits_per_pixel>8 && bits_per_pixel<16) // make lut table safe for 10-14 bit garbage
1727 2 std::fill_n((uint16_t *)map, map_size / pixelsize, max_pixel_value);
1728
1729
2/2
✓ Branch 86 → 87 taken 1 time.
✓ Branch 86 → 88 taken 2 times.
3 int range_low = coring ? limits.tv_range_low : 0;
1730
2/2
✓ Branch 89 → 90 taken 1 time.
✓ Branch 89 → 91 taken 2 times.
3 int range_high = coring ? limits.tv_range_hi_luma : max_pixel_value;
1731
1732 // dither_scale_luma = 1 if no dither, 256 if dither
1733 /* create luma lut for brightness and contrast */
1734
2/2
✓ Branch 116 → 93 taken 1536 times.
✓ Branch 116 → 117 taken 3 times.
1539 for (int i = 0; i < lut_size * scale_dither_luma; i++) {
1735 int ii;
1736
1/2
✗ Branch 93 → 94 not taken.
✓ Branch 93 → 95 taken 1536 times.
1536 if(dither) {
1737 ii = (i & 0xFFFFFF00) + (int)((i & 0xFF)*dither_strength);
1738 } else {
1739 1536 ii = i;
1740 }
1741 // _bright param range is accepted as 0..256
1742 1536 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);
1743
1744 // coring, dither:
1745 // int y = int(((ii - 16 * 256)*_cont + _bright * 256 - 127.5) / 256 + 16.5); // 256 _cont & _bright param range
1746 // coring, no dither:
1747 // int y = int(((ii - 16)*_cont + _bright) + 16.5); // 256 _cont & _bright param range
1748 // no coring, dither:
1749 // int y = int((ii *_cont + _bright * 256 - 127.5) / 256 + 0.5 ); // 256 _cont & _bright param range
1750 // no coring, no dither:
1751 // int y = int((ii *_cont + _bright) + 0.5 ); // 256 _cont & _bright param range
1752
2/2
✓ Branch 96 → 97 taken 512 times.
✓ Branch 96 → 106 taken 1024 times.
1536 if(pixelsize==1)
1753 512 map[i] = (BYTE)clamp(y, range_low, range_high);
1754 else
1755 1024 reinterpret_cast<uint16_t *>(map)[i] = (uint16_t)clamp(y, range_low, range_high);
1756 }
1757 }
1758 // 100% equals sat=119 (= maximal saturation of valid RGB (R=255,G=B=0)
1759 // 150% (=180) - 100% (=119) overshoot
1760 13 const double minSat = 1.19 * _minSat;
1761 13 const double maxSat = 1.19 * _maxSat;
1762
1763 13 p *= 1.19; // Same units as minSat/maxSat
1764
1765
6/8
✓ Branch 117 → 118 taken 10 times.
✓ Branch 117 → 120 taken 3 times.
✓ Branch 118 → 119 taken 10 times.
✗ Branch 118 → 275 not taken.
✗ Branch 119 → 120 not taken.
✓ Branch 119 → 121 taken 10 times.
✓ Branch 122 → 123 taken 3 times.
✓ Branch 122 → 269 taken 10 times.
13 if (!(realcalc_chroma && vi.IsPlanar()))
1766 { // fill lookup tables for UV
1767 3 size_t map_size = pixelsize * lut_size * lut_size * 2 * scale_dither_chroma;
1768 // for 10 bit with dither: 2 * 1024 * 1024 * 2 * 4 = 4*64 MByte = 256M huh!
1769 // for 10 bit w/o dither: 2 * 1024 * 1024 * 2 = 64 MByte
1770
1771
1/2
✓ Branch 123 → 124 taken 3 times.
✗ Branch 123 → 275 not taken.
3 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)
1772
1/2
✗ Branch 124 → 125 not taken.
✓ Branch 124 → 126 taken 3 times.
3 if (!mapUV)
1773 env->ThrowError("Tweak: Could not reserve memory.");
1774
1/2
✓ Branch 126 → 127 taken 3 times.
✗ Branch 126 → 275 not taken.
3 env->AtExit(free_buffer, mapUV);
1775
1776
2/2
✓ Branch 127 → 128 taken 1 time.
✓ Branch 127 → 129 taken 2 times.
3 int range_low = coring ? limits.tv_range_low : 0;
1777
2/2
✓ Branch 130 → 131 taken 1 time.
✓ Branch 130 → 132 taken 2 times.
3 int range_high = coring ? limits.tv_range_hi_chroma : max_pixel_value;
1778
1779 3 double uv_range_corr = 1.0 / (1 << (bits_per_pixel - 8));
1780
1781
1/2
✗ Branch 133 → 134 not taken.
✓ Branch 133 → 203 taken 3 times.
3 if (dither) {
1782 // lut chroma, dither
1783 for (int d = 0; d < scale_dither_chroma; d++) { // scale = 4 0..15 mini-dither
1784 for (int u = 0; u < lut_size; u++) {
1785 // dither_strength: optional correction for 8+ bit to have the same dither range as in 8 bits
1786 const double destu = (((u << 4) + d*dither_strength) + bias_dither_chroma) / scale_dither_chroma - limits.middle_chroma; // scale_dither_chroma: 16
1787 for (int v = 0; v < lut_size; v++) {
1788 const double destv = (((v << 4) + d*dither_strength) + bias_dither_chroma) / scale_dither_chroma - limits.middle_chroma;
1789 int iSat = Sat;
1790 if (allPixels || ProcessPixel(destv * uv_range_corr, destu * uv_range_corr, _startHue, _endHue, maxSat, minSat, p, iSat)) {
1791 int du = (int)((destu*COS + destv*SIN) * iSat + 0x100) >> 9; // back from the extra 9 bits Sat precision
1792 int dv = (int)((destv*COS - destu*SIN) * iSat + 0x100) >> 9;
1793 du = clamp(du + limits.middle_chroma, range_low, range_high);
1794 dv = clamp(dv + limits.middle_chroma, range_low, range_high);
1795 if(pixelsize==1)
1796 mapUV[(u << 12) | (v << 4) | d] = (uint16_t)(du | (dv << 8)); // U and V: two bytes
1797 else
1798 reinterpret_cast<uint32_t *>(mapUV)[(u << (4+bits_per_pixel)) | (v << 4) | d] = (uint32_t)(du | (dv << 16)); // U and V: two words
1799 }
1800 else {
1801 if(pixelsize==1)
1802 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
1803 else
1804 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
1805 }
1806 }
1807 }
1808 }
1809 }
1810 else {
1811 // lut chroma, no dither
1812
2/2
✓ Branch 268 → 204 taken 1536 times.
✓ Branch 268 → 269 taken 3 times.
1539 for (int u = 0; u < lut_size; u++) {
1813 1536 const double destu = u - limits.middle_chroma;
1814
2/2
✓ Branch 266 → 205 taken 1179648 times.
✓ Branch 266 → 267 taken 1536 times.
1181184 for (int v = 0; v < lut_size; v++) {
1815 1179648 const double destv = v - limits.middle_chroma;
1816 1179648 int iSat = Sat;
1817
7/8
✓ Branch 205 → 206 taken 65536 times.
✓ Branch 205 → 208 taken 1114112 times.
✓ Branch 206 → 207 taken 65536 times.
✗ Branch 206 → 274 not taken.
✓ Branch 207 → 208 taken 6434 times.
✓ Branch 207 → 209 taken 59102 times.
✓ Branch 210 → 211 taken 1120546 times.
✓ Branch 210 → 230 taken 59102 times.
1179648 if (allPixels || ProcessPixel(destv * uv_range_corr, destu * uv_range_corr, _startHue, _endHue, maxSat, minSat, p, iSat)) {
1818 1120546 int du = int((destu*COS + destv*SIN) * iSat) >> 9; // back from the extra 9 bits Sat precision
1819 1120546 int dv = int((destv*COS - destu*SIN) * iSat) >> 9;
1820
2/2
✓ Branch 211 → 212 taken 155648 times.
✓ Branch 211 → 213 taken 964898 times.
1120546 du = clamp(du + limits.middle_chroma, range_low, range_high);
1821
2/2
✓ Branch 219 → 220 taken 155648 times.
✓ Branch 219 → 221 taken 964898 times.
1120546 dv = clamp(dv + limits.middle_chroma, range_low, range_high);
1822
2/2
✓ Branch 227 → 228 taken 71970 times.
✓ Branch 227 → 229 taken 1048576 times.
1120546 if(pixelsize==1)
1823 71970 mapUV[(u << 8) | v] = (uint16_t)(du | (dv << 8)); // U and V: two bytes
1824 else
1825 1048576 reinterpret_cast<uint32_t *>(mapUV)[(u << bits_per_pixel) | v] = (uint32_t)(du | (dv << 16)); // U and V: two words
1826 }
1827 else {
1828
1/2
✓ Branch 230 → 231 taken 59102 times.
✗ Branch 230 → 248 not taken.
59102 if(pixelsize==1)
1829
1/2
✗ Branch 239 → 240 not taken.
✓ Branch 239 → 241 taken 59102 times.
118204 mapUV[(u << 8) | v] = (uint16_t)(clamp(u, range_low, range_high) | (clamp(v, range_low, range_high) << 8)); // U and V: two bytes
1830 else
1831 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
1832 }
1833 }
1834 }
1835 }
1836 }
1837 13 }
1838
1839
1840 template<typename pixel_t, bool dither>
1841 10 void Tweak::tweak_calc_chroma(BYTE *srcpu, BYTE *srcpv, int src_pitch, int width, int height, float minUV, float maxUV)
1842 {
1843 // no lookup, alway true for 16/32 bit, optional for 8 bit
1844 10 const double Hue = (dhue * PI) / 180.0;
1845 // 100% equals sat=119 (= maximal saturation of valid RGB (R=255,G=B=0)
1846 // 150% (=180) - 100% (=119) overshoot
1847 10 const double minSat = 1.19 * dminSat;
1848 10 const double maxSat = 1.19 * dmaxSat;
1849
1850 10 const double p = dinterp * 1.19; // Same units as minSat/maxSat
1851
1852 10 const int minUVi = (int)minUV;
1853 10 const int maxUVi = (int)maxUV;
1854
1855 10 float ditherval = 0.0;
1856 float u, v;
1857 10 const float cosHue = (float)cos(Hue);
1858 10 const float sinHue = (float)sin(Hue);
1859 // no lut, realcalc, float internals
1860 10 const float pixel_range = sizeof(pixel_t) == 4 ? 1.0f : (float)(max_pixel_value + 1);
1861
1862 10 double uv_range_corr = 255.0;
1863
1864 10 const bool isFloat = sizeof(pixel_t) == 4;
1865
1866
10/12
void Tweak::tweak_calc_chroma<float, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 49 → 3 taken 4 times.
✓ Branch 49 → 50 taken 2 times.
void Tweak::tweak_calc_chroma<float, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 49 → 3 taken 4 times.
✓ Branch 49 → 50 taken 2 times.
void Tweak::tweak_calc_chroma<unsigned char, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 49 → 3 taken 2 times.
✓ Branch 49 → 50 taken 2 times.
void Tweak::tweak_calc_chroma<unsigned char, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 49 → 3 not taken.
✗ Branch 49 → 50 not taken.
void Tweak::tweak_calc_chroma<unsigned short, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 49 → 3 taken 8 times.
✓ Branch 49 → 50 taken 3 times.
void Tweak::tweak_calc_chroma<unsigned short, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 49 → 3 taken 3 times.
✓ Branch 49 → 50 taken 1 time.
31 for (int y = 0; y < height; ++y) {
1867 21 const int _y = (y << 2) & 0xC;
1868
10/12
void Tweak::tweak_calc_chroma<float, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 47 → 4 taken 24 times.
✓ Branch 47 → 48 taken 4 times.
void Tweak::tweak_calc_chroma<float, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 47 → 4 taken 20 times.
✓ Branch 47 → 48 taken 4 times.
void Tweak::tweak_calc_chroma<unsigned char, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 47 → 4 taken 16 times.
✓ Branch 47 → 48 taken 2 times.
void Tweak::tweak_calc_chroma<unsigned char, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 47 → 4 not taken.
✗ Branch 47 → 48 not taken.
void Tweak::tweak_calc_chroma<unsigned short, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 47 → 4 taken 38 times.
✓ Branch 47 → 48 taken 8 times.
void Tweak::tweak_calc_chroma<unsigned short, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 47 → 4 taken 12 times.
✓ Branch 47 → 48 taken 3 times.
131 for (int x = 0; x < width; ++x) {
1869 if (dither)
1870 32 ditherval = ((float(ditherMap4[(x & 0x3) | _y]) * dither_strength + bias_dither_chroma) / scale_dither_chroma); // +/-0.5 on 0..255 range
1871 110 pixel_t orig_u = reinterpret_cast<pixel_t *>(srcpu)[x];
1872 110 pixel_t orig_v = reinterpret_cast<pixel_t *>(srcpv)[x] ;
1873 110 u = isFloat ? (orig_u - limits.middle_chroma_f) : (orig_u - limits.middle_chroma);
1874 110 v = isFloat ? (orig_v - limits.middle_chroma_f) : (orig_v - limits.middle_chroma);
1875
1876 110 u = (u + (dither ? ditherval : 0)) / (sizeof(pixel_t) == 4 ? 1.0f : pixel_range); // going from 0..1 to +/-0.5
1877 110 v = (v + (dither ? ditherval : 0)) / (sizeof(pixel_t) == 4 ? 1.0f : pixel_range);
1878
1879 110 double dWorkSat = dsat; // init from original param
1880
15/48
void Tweak::tweak_calc_chroma<float, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 4 → 5 taken 14 times.
✓ Branch 4 → 7 taken 10 times.
✓ Branch 5 → 6 taken 14 times.
✗ Branch 5 → 51 not taken.
✓ Branch 6 → 7 taken 6 times.
✓ Branch 6 → 8 taken 8 times.
✓ Branch 9 → 10 taken 16 times.
✓ Branch 9 → 29 taken 8 times.
void Tweak::tweak_calc_chroma<float, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 20 times.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 51 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✓ Branch 9 → 10 taken 20 times.
✗ Branch 9 → 29 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 → 51 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✓ Branch 9 → 10 taken 16 times.
✗ Branch 9 → 29 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 → 51 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 29 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 38 times.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 51 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✓ Branch 9 → 10 taken 38 times.
✗ Branch 9 → 29 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 → 51 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✓ Branch 9 → 10 taken 12 times.
✗ Branch 9 → 29 not taken.
110 if(allPixels || ProcessPixelUnscaled(v * uv_range_corr, u * uv_range_corr, dstartHue, dendHue, maxSat, minSat, p, dWorkSat))
1881 {
1882 102 float du = ((u*cosHue + v*sinHue) * (float)dWorkSat);
1883 102 float dv = ((v*cosHue - u*sinHue) * (float)dWorkSat);
1884
1885 if (isFloat) {
1886 36 du = du + limits.middle_chroma_f;
1887 36 dv = dv + limits.middle_chroma_f;
1888 }
1889 else {
1890 // back to 0..1
1891 66 du = du + 0.5f;
1892 66 dv = dv + 0.5f;
1893 }
1894
1895 if(isFloat) {
1896
4/4
void Tweak::tweak_calc_chroma<float, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 12 → 13 taken 2 times.
✓ Branch 12 → 14 taken 14 times.
void Tweak::tweak_calc_chroma<float, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 12 → 13 taken 4 times.
✓ Branch 12 → 14 taken 16 times.
36 reinterpret_cast<pixel_t *>(srcpu)[x] = (pixel_t)clamp(du, minUV, maxUV);
1897
4/4
void Tweak::tweak_calc_chroma<float, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 20 → 21 taken 2 times.
✓ Branch 20 → 22 taken 14 times.
void Tweak::tweak_calc_chroma<float, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 20 → 21 taken 4 times.
✓ Branch 20 → 22 taken 16 times.
72 reinterpret_cast<pixel_t *>(srcpv)[x] = (pixel_t)clamp(dv, minUV, maxUV);
1898 } else {
1899
4/8
void Tweak::tweak_calc_chroma<unsigned char, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 16 times.
void Tweak::tweak_calc_chroma<unsigned char, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 14 not taken.
void Tweak::tweak_calc_chroma<unsigned short, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 12 → 13 taken 4 times.
✓ Branch 12 → 14 taken 34 times.
void Tweak::tweak_calc_chroma<unsigned short, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 12 times.
66 reinterpret_cast<pixel_t *>(srcpu)[x] = (pixel_t)clamp((int)(du * pixel_range), minUVi, maxUVi);
1900
4/8
void Tweak::tweak_calc_chroma<unsigned char, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 16 times.
void Tweak::tweak_calc_chroma<unsigned char, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 22 not taken.
void Tweak::tweak_calc_chroma<unsigned short, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✓ Branch 20 → 21 taken 4 times.
✓ Branch 20 → 22 taken 34 times.
void Tweak::tweak_calc_chroma<unsigned short, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 12 times.
132 reinterpret_cast<pixel_t *>(srcpv)[x] = (pixel_t)clamp((int)(dv * pixel_range), minUVi, maxUVi);
1901 }
1902 }
1903 else {
1904 if(isFloat) {
1905
1/4
void Tweak::tweak_calc_chroma<float, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 8 times.
void Tweak::tweak_calc_chroma<float, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 31 not taken.
8 reinterpret_cast<pixel_t *>(srcpu)[x] = (pixel_t)clamp((float)orig_u, minUV, maxUV);
1906
1/4
void Tweak::tweak_calc_chroma<float, false>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 8 times.
void Tweak::tweak_calc_chroma<float, true>(unsigned char*, unsigned char*, int, int, int, float, float):
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 39 not taken.
16 reinterpret_cast<pixel_t *>(srcpv)[x] = (pixel_t)clamp((float)orig_v, minUV, maxUV);
1907 } else {
1908 reinterpret_cast<pixel_t *>(srcpu)[x] = (pixel_t)clamp((int)(orig_u), minUVi, maxUVi);
1909 reinterpret_cast<pixel_t *>(srcpv)[x] = (pixel_t)clamp((int)(orig_v), minUVi, maxUVi);
1910 }
1911 }
1912 }
1913 21 srcpu += src_pitch;
1914 21 srcpv += src_pitch;
1915 }
1916
1917 10 }
1918
1919
1920 13 PVideoFrame __stdcall Tweak::GetFrame(int n, IScriptEnvironment* env)
1921 {
1922 13 PVideoFrame src = child->GetFrame(n, env);
1923
1/2
✓ Branch 4 → 5 taken 13 times.
✗ Branch 4 → 183 not taken.
13 env->MakeWritable(&src);
1924
1925
1/2
✓ Branch 6 → 7 taken 13 times.
✗ Branch 6 → 183 not taken.
13 BYTE* srcp = src->GetWritePtr();
1926
1927
1/2
✓ Branch 8 → 9 taken 13 times.
✗ Branch 8 → 183 not taken.
13 int src_pitch = src->GetPitch();
1928
1/2
✓ Branch 10 → 11 taken 13 times.
✗ Branch 10 → 183 not taken.
13 int height = src->GetHeight();
1929
1/2
✓ Branch 12 → 13 taken 13 times.
✗ Branch 12 → 183 not taken.
13 int row_size = src->GetRowSize();
1930
1931
2/4
✓ Branch 13 → 14 taken 13 times.
✗ Branch 13 → 183 not taken.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 31 taken 13 times.
13 if (vi.IsYUY2()) {
1932
1933 if (dither) {
1934 const int UVwidth = vi.width / 2;
1935 for (int y = 0; y < height; y++) {
1936 {const int _y = (y << 4) & 0xf0;
1937 for (int x = 0; x < vi.width; ++x) {
1938 /* brightness and contrast */
1939 srcp[x * 2] = map[srcp[x * 2] << 8 | ditherMap[(x & 0x0f) | _y]];
1940 }}
1941 {const int _y = (y << 2) & 0xC;
1942 for (int x = 0; x < UVwidth; ++x) {
1943 const int _dither = ditherMap4[(x & 0x3) | _y];
1944 /* hue and saturation */
1945 const int u = srcp[x * 4 + 1];
1946 const int v = srcp[x * 4 + 3];
1947 const int mapped = mapUV[(u << 12) | (v << 4) | _dither];
1948 srcp[x * 4 + 1] = (BYTE)(mapped & 0xff);
1949 srcp[x * 4 + 3] = (BYTE)(mapped >> 8);
1950 }}
1951 srcp += src_pitch;
1952 }
1953 }
1954 else {
1955 for (int y = 0; y < height; y++)
1956 {
1957 for (int x = 0; x < row_size; x += 4)
1958 {
1959 /* brightness and contrast */
1960 srcp[x] = map[srcp[x]];
1961 srcp[x + 2] = map[srcp[x + 2]];
1962
1963 /* hue and saturation */
1964 const int u = srcp[x + 1];
1965 const int v = srcp[x + 3];
1966 const int mapped = mapUV[(u << 8) | v];
1967 srcp[x + 1] = (BYTE)(mapped & 0xff);
1968 srcp[x + 3] = (BYTE)(mapped >> 8);
1969 }
1970 srcp += src_pitch;
1971 }
1972 }
1973 // YUY2 end
1974 }
1975
2/4
✓ Branch 31 → 32 taken 13 times.
✗ Branch 31 → 183 not taken.
✓ Branch 32 → 33 taken 13 times.
✗ Branch 32 → 181 not taken.
13 else if (vi.IsPlanar()) {
1976 // brightness and contrast
1977 // no_lut and lut
1978 13 int width = row_size / pixelsize;
1979
2/2
✓ Branch 33 → 34 taken 10 times.
✓ Branch 33 → 61 taken 3 times.
13 if (realcalc_luma)
1980 {
1981 // no luma lookup! alway true for 32 bit, optional for 8-16 bits
1982 float maxY;
1983 float minY;
1984 // unique for each bit-depth, difference in the innermost loop (speed)
1985
2/2
✓ Branch 34 → 35 taken 2 times.
✓ Branch 34 → 36 taken 8 times.
10 maxY = (float)(coring ? limits.tv_range_hi_luma : max_pixel_value);
1986
2/2
✓ Branch 37 → 38 taken 2 times.
✓ Branch 37 → 39 taken 8 times.
10 minY = (float)(coring ? limits.tv_range_low : 0);
1987
1988
2/2
✓ Branch 40 → 41 taken 2 times.
✓ Branch 40 → 44 taken 8 times.
10 if(pixelsize == 1) {
1989
1/2
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 43 taken 2 times.
2 if(dither)
1990 tweak_calc_luma<uint8_t, false, true>(srcp, src_pitch, minY, maxY, width, height);
1991 else
1992 2 tweak_calc_luma<uint8_t, false, false>(srcp, src_pitch, minY, maxY, width, height);
1993
2/2
✓ Branch 44 → 45 taken 1 time.
✓ Branch 44 → 48 taken 7 times.
8 } else if (bits_per_pixel < 16) {
1994
1/2
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 1 time.
1 if(dither)
1995 tweak_calc_luma<uint16_t, true, true>(srcp, src_pitch, minY, maxY, width, height);
1996 else
1997 1 tweak_calc_luma<uint16_t, true, false>(srcp, src_pitch, minY, maxY, width, height);
1998
2/2
✓ Branch 48 → 49 taken 3 times.
✓ Branch 48 → 52 taken 4 times.
7 } else if(bits_per_pixel == 16) {
1999
2/2
✓ Branch 49 → 50 taken 1 time.
✓ Branch 49 → 51 taken 2 times.
3 if(dither)
2000 1 tweak_calc_luma<uint16_t, false, true>(srcp, src_pitch, minY, maxY, width, height);
2001 else
2002 2 tweak_calc_luma<uint16_t, false, false>(srcp, src_pitch, minY, maxY, width, height);
2003 } else { // float
2004
2/2
✓ Branch 52 → 53 taken 1 time.
✓ Branch 52 → 54 taken 3 times.
4 maxY = coring ? 235.0f / 256 : 1.0f; // scale into 0..1 range
2005
2/2
✓ Branch 55 → 56 taken 1 time.
✓ Branch 55 → 57 taken 3 times.
4 minY = coring ? 16.0f / 256 : 0;
2006
2/2
✓ Branch 58 → 59 taken 2 times.
✓ Branch 58 → 60 taken 2 times.
4 if(dither)
2007 2 tweak_calc_luma<float, false, true>(srcp, src_pitch, minY, maxY, width, height);
2008 else
2009 2 tweak_calc_luma<float, false, false>(srcp, src_pitch, minY, maxY, width, height);
2010 }
2011 }
2012 else {
2013 /* brightness and contrast */
2014 // use luma lookup for 8-16 bits
2015
1/2
✗ Branch 61 → 62 not taken.
✓ Branch 61 → 75 taken 3 times.
3 if (dither) {
2016 if(pixelsize==1) {
2017 for (int y = 0; y < height; ++y) {
2018 const int _y = (y << 4) & 0xf0;
2019 for (int x = 0; x < width; ++x) {
2020 /* brightness and contrast */
2021 srcp[x] = map[srcp[x] << 8 | ditherMap[(x & 0x0f) | _y]];
2022 }
2023 srcp += src_pitch;
2024 }
2025 }
2026 else { // pixelsize == 2
2027 for (int y = 0; y < height; ++y) {
2028 const int _y = (y << 4) & 0xf0;
2029 for (int x = 0; x < width; ++x) {
2030 reinterpret_cast<uint16_t *>(srcp)[x] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(srcp)[x] << 8 | ditherMap[(x & 0x0f) | _y]];
2031 // no clamp, map is safely sized
2032 }
2033 srcp += src_pitch;
2034 }
2035 }
2036 }
2037 else {
2038
2/2
✓ Branch 75 → 76 taken 2 times.
✓ Branch 75 → 82 taken 1 time.
3 if(pixelsize==1) {
2039
2/2
✓ Branch 81 → 77 taken 5 times.
✓ Branch 81 → 88 taken 2 times.
7 for (int y = 0; y < height; ++y) {
2040
2/2
✓ Branch 79 → 78 taken 37 times.
✓ Branch 79 → 80 taken 5 times.
42 for (int x = 0; x < width; ++x) {
2041 37 srcp[x] = map[srcp[x]];
2042 }
2043 5 srcp += src_pitch;
2044 }
2045 }
2046 else { // pixelsize == 2
2047
2/2
✓ Branch 87 → 83 taken 2 times.
✓ Branch 87 → 88 taken 1 time.
3 for (int y = 0; y < height; ++y) {
2048
2/2
✓ Branch 85 → 84 taken 14 times.
✓ Branch 85 → 86 taken 2 times.
16 for (int x = 0; x < width; ++x) {
2049 14 reinterpret_cast<uint16_t *>(srcp)[x] = reinterpret_cast<uint16_t *>(map)[reinterpret_cast<uint16_t *>(srcp)[x]];
2050 // no clamp, map is safely sized
2051 }
2052 2 srcp += src_pitch;
2053 }
2054 }
2055 }
2056 }
2057 // Y: brightness and contrast done
2058
2059 // UV: hue and saturation start
2060
1/2
✓ Branch 89 → 90 taken 13 times.
✗ Branch 89 → 183 not taken.
13 src_pitch = src->GetPitch(PLANAR_U);
2061
1/2
✓ Branch 91 → 92 taken 13 times.
✗ Branch 91 → 183 not taken.
13 BYTE * srcpu = src->GetWritePtr(PLANAR_U);
2062
1/2
✓ Branch 93 → 94 taken 13 times.
✗ Branch 93 → 183 not taken.
13 BYTE * srcpv = src->GetWritePtr(PLANAR_V);
2063
1/2
✓ Branch 95 → 96 taken 13 times.
✗ Branch 95 → 183 not taken.
13 row_size = src->GetRowSize(PLANAR_U);
2064
1/2
✓ Branch 97 → 98 taken 13 times.
✗ Branch 97 → 183 not taken.
13 height = src->GetHeight(PLANAR_U);
2065 13 width = row_size / pixelsize;
2066
2067
2/2
✓ Branch 98 → 99 taken 10 times.
✓ Branch 98 → 122 taken 3 times.
13 if (realcalc_chroma) {
2068 // no lookup, alway true for > 10 bit, optional for 8/10 bit
2069
2/2
✓ Branch 99 → 100 taken 2 times.
✓ Branch 99 → 101 taken 8 times.
10 float maxUV = (float)(coring ? limits.tv_range_hi_chroma : max_pixel_value);
2070
2/2
✓ Branch 102 → 103 taken 2 times.
✓ Branch 102 → 104 taken 8 times.
10 float minUV = (float)(coring ? limits.tv_range_low : 0);
2071
2/2
✓ Branch 105 → 106 taken 2 times.
✓ Branch 105 → 109 taken 8 times.
10 if(pixelsize == 1) {
2072
1/2
✗ Branch 106 → 107 not taken.
✓ Branch 106 → 108 taken 2 times.
2 if (dither)
2073 tweak_calc_chroma<uint8_t, true>(srcpu, srcpv, src_pitch, width, height, minUV, maxUV);
2074 else
2075
1/2
✓ Branch 108 → 181 taken 2 times.
✗ Branch 108 → 183 not taken.
2 tweak_calc_chroma<uint8_t, false>(srcpu, srcpv, src_pitch, width, height, minUV, maxUV);
2076
2/2
✓ Branch 109 → 110 taken 4 times.
✓ Branch 109 → 113 taken 4 times.
8 } else if(pixelsize==2) {
2077
2/2
✓ Branch 110 → 111 taken 1 time.
✓ Branch 110 → 112 taken 3 times.
4 if (dither)
2078
1/2
✓ Branch 111 → 181 taken 1 time.
✗ Branch 111 → 183 not taken.
1 tweak_calc_chroma<uint16_t, true>(srcpu, srcpv, src_pitch, width, height, minUV, maxUV);
2079 else
2080
1/2
✓ Branch 112 → 181 taken 3 times.
✗ Branch 112 → 183 not taken.
3 tweak_calc_chroma<uint16_t, false>(srcpu, srcpv, src_pitch, width, height, minUV, maxUV);
2081 } else { // pixelsize == 4
2082
2/2
✓ Branch 113 → 114 taken 1 time.
✓ Branch 113 → 115 taken 3 times.
4 maxUV = coring ? limits.tv_range_hi_chroma_f : limits.full_range_hi_chroma_f;
2083
2/2
✓ Branch 116 → 117 taken 1 time.
✓ Branch 116 → 118 taken 3 times.
4 minUV = coring ? limits.tv_range_low_chroma_f : limits.full_range_low_chroma_f;
2084
2/2
✓ Branch 119 → 120 taken 2 times.
✓ Branch 119 → 121 taken 2 times.
4 if (dither)
2085
1/2
✓ Branch 120 → 181 taken 2 times.
✗ Branch 120 → 183 not taken.
2 tweak_calc_chroma<float, true>(srcpu, srcpv, src_pitch, width, height, minUV, maxUV);
2086 else
2087
1/2
✓ Branch 121 → 181 taken 2 times.
✗ Branch 121 → 183 not taken.
2 tweak_calc_chroma<float, false>(srcpu, srcpv, src_pitch, width, height, minUV, maxUV);
2088 }
2089 }
2090 else { // lookup UV
2091
1/2
✗ Branch 122 → 123 not taken.
✓ Branch 122 → 152 taken 3 times.
3 if (dither) {
2092 // lut + dither
2093 if(pixelsize==1) {
2094 for (int y = 0; y < height; ++y) {
2095 const int _y = (y << 2) & 0xC;
2096 for (int x = 0; x < width; ++x) {
2097 const int _dither = ditherMap4[(x & 0x3) | _y];
2098 /* hue and saturation */
2099 const int u = srcpu[x];
2100 const int v = srcpv[x];
2101 const int mapped = mapUV[(u << 12) | (v << 4) | _dither];
2102 srcpu[x] = (BYTE)(mapped & 0xff);
2103 srcpv[x] = (BYTE)(mapped >> 8);
2104 }
2105 srcpu += src_pitch;
2106 srcpv += src_pitch;
2107 }
2108 }
2109 else { // pixelsize == 2
2110 for (int y = 0; y < height; ++y) {
2111 const int _y = (y << 2) & 0xC;
2112 for (int x = 0; x < width; ++x) {
2113 const int _dither = ditherMap4[(x & 0x3) | _y]; // 0..15
2114 /* hue and saturation */
2115 const int u = clamp(0,(int)reinterpret_cast<uint16_t *>(srcpu)[x], max_pixel_value);
2116 const int v = clamp(0,(int)reinterpret_cast<uint16_t *>(srcpv)[x], max_pixel_value);
2117 const unsigned int mapped = reinterpret_cast<uint32_t *>(mapUV)[(u << (4+bits_per_pixel)) | (v << 4) | _dither];
2118 reinterpret_cast<uint16_t *>(srcpu)[x] = (uint16_t)(mapped & 0xffff);
2119 reinterpret_cast<uint16_t *>(srcpv)[x] = (uint16_t)(mapped >> 16);
2120 }
2121 srcpu += src_pitch;
2122 srcpv += src_pitch;
2123 }
2124 }
2125 }
2126 else {
2127 // lut + no dither
2128
2/2
✓ Branch 152 → 153 taken 2 times.
✓ Branch 152 → 159 taken 1 time.
3 if(pixelsize==1) {
2129
2/2
✓ Branch 158 → 154 taken 5 times.
✓ Branch 158 → 181 taken 2 times.
7 for (int y = 0; y < height; ++y) {
2130
2/2
✓ Branch 156 → 155 taken 37 times.
✓ Branch 156 → 157 taken 5 times.
42 for (int x = 0; x < width; ++x) {
2131 /* hue and saturation */
2132 37 const int u = srcpu[x];
2133 37 const int v = srcpv[x];
2134 37 const int mapped = mapUV[(u << 8) | v];
2135 37 srcpu[x] = (BYTE)(mapped & 0xff);
2136 37 srcpv[x] = (BYTE)(mapped >> 8);
2137 }
2138 5 srcpu += src_pitch;
2139 5 srcpv += src_pitch;
2140 }
2141 }
2142 else { // pixelsize == 2
2143
2/2
✓ Branch 180 → 160 taken 2 times.
✓ Branch 180 → 181 taken 1 time.
3 for (int y = 0; y < height; ++y) {
2144
2/2
✓ Branch 178 → 161 taken 14 times.
✓ Branch 178 → 179 taken 2 times.
16 for (int x = 0; x < width; ++x) {
2145
1/2
✗ Branch 161 → 162 not taken.
✓ Branch 161 → 163 taken 14 times.
14 const int u = clamp(0,(int)reinterpret_cast<uint16_t *>(srcpu)[x], max_pixel_value);
2146
1/2
✗ Branch 169 → 170 not taken.
✓ Branch 169 → 171 taken 14 times.
14 const int v = clamp(0,(int)reinterpret_cast<uint16_t *>(srcpv)[x], max_pixel_value);
2147 14 const unsigned int mapped = reinterpret_cast<uint32_t *>(mapUV)[(u << bits_per_pixel) | v];
2148 14 reinterpret_cast<uint16_t *>(srcpu)[x] = (uint16_t)(mapped & 0xffff);
2149 14 reinterpret_cast<uint16_t *>(srcpv)[x] = (uint16_t)(mapped >> 16);
2150 }
2151 2 srcpu += src_pitch;
2152 2 srcpv += src_pitch;
2153 }
2154 }
2155 }
2156 }
2157 }
2158
2159 13 return src;
2160 }
2161
2162 AVSValue __cdecl Tweak::Create(AVSValue args, void* , IScriptEnvironment* env)
2163 {
2164 return new Tweak(args[0].AsClip(),
2165 args[1].AsDblDef(0.0), // hue
2166 args[2].AsDblDef(1.0), // sat
2167 args[3].AsDblDef(0.0), // bright
2168 args[4].AsDblDef(1.0), // cont
2169 args[5].AsBool(true), // coring
2170 // not used even on intel. // args[6].AsBool(false), // sse
2171 args[7].AsDblDef(0.0), // startHue
2172 args[8].AsDblDef(360.0), // endHue
2173 args[9].AsDblDef(150.0), // maxSat
2174 args[10].AsDblDef(0.0), // minSat
2175 args[11].AsDblDef(16.0 / 1.19),// interp
2176 args[12].AsBool(false), // dither
2177 args[13].AsBool(false), // realcalc: force no-lookup (pure float calculation pixel)
2178 args[14].AsDblDef(1.0), // dither_strength 1.0 = +/-0.5 on the 0.255 range, scaled for others
2179 env);
2180 }
2181
2182 /**********************
2183 ****** MaskHS *****
2184 **********************/
2185
2186 11 MaskHS::MaskHS(PClip _child, double _startHue, double _endHue, double _maxSat, double _minSat, bool _coring, bool _realcalc,
2187 11 IScriptEnvironment* env)
2188
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)
2189 {
2190
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())
2191 env->ThrowError("MaskHS: YUV data only (no RGB)");
2192
2193
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) {
2194 env->ThrowError("MaskHS: clip must contain chroma.");
2195 }
2196
2197
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)
2198
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");
2199
2200
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)
2201
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");
2202
2203
2/2
✓ Branch 17 → 18 taken 2 times.
✓ Branch 17 → 19 taken 5 times.
7 if (dminSat >= dmaxSat)
2204
1/2
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 89 taken 2 times.
2 env->ThrowError("MaskHS: MinSat must be less than MaxSat");
2205
2206
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)
2207
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.");
2208
2209
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)
2210
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.");
2211
2212
1/2
✓ Branch 25 → 26 taken 3 times.
✗ Branch 25 → 89 not taken.
3 pixelsize = vi.ComponentSize();
2213
1/2
✓ Branch 26 → 27 taken 3 times.
✗ Branch 26 → 89 not taken.
3 bits_per_pixel = vi.BitsPerComponent();
2214 3 max_pixel_value = (1 << bits_per_pixel) - 1;
2215 3 lut_size = 1 << bits_per_pixel;
2216
2217 3 get_limits(limits, bits_per_pixel);
2218
2219
2/2
✓ Branch 28 → 29 taken 2 times.
✓ Branch 28 → 30 taken 1 time.
3 mask_low = coring ? limits.tv_range_low : 0;
2220
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;
2221
2222
1/2
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 42 taken 3 times.
3 if (bits_per_pixel == 32) {
2223 mask_low_f = coring ? limits.tv_range_low_luma_f : limits.full_range_low_luma_f;
2224 mask_high_f = coring ? limits.tv_range_hi_luma_f : limits.full_range_hi_luma_f;
2225 }
2226
2227 3 realcalc_chroma = realcalc;
2228
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
2229 realcalc_chroma = true;
2230
2231 // 100% equals sat=119 (= maximal saturation of valid RGB (R=255,G=B=0)
2232 // 150% (=180) - 100% (=119) overshoot
2233 3 minSat = 1.19 * dminSat;
2234 3 maxSat = 1.19 * dmaxSat;
2235
2236
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()))
2237 { // fill lookup tables for UV
2238 1 size_t map_size = pixelsize * lut_size * lut_size;
2239 // for 8 bit : 1 * 256 * 256 = 65536 byte
2240 // for 10 bit : 2 * 1024 * 1024 = 2 MByte
2241 // for 12 bit : 2 * 4096 * 4096 = 32 MByte
2242
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)
2243
1/2
✗ Branch 56 → 57 not taken.
✓ Branch 56 → 58 taken 1 time.
1 if (!mapUV)
2244 env->ThrowError("Tweak: Could not reserve memory.");
2245
1/2
✓ Branch 58 → 59 taken 1 time.
✗ Branch 58 → 89 not taken.
1 env->AtExit(free_buffer, mapUV);
2246
2247 // apply mask
2248 1 double uv_range_corr = 1.0 / (1 << (bits_per_pixel - 8)); // no float here
2249
2/2
✓ Branch 74 → 60 taken 256 times.
✓ Branch 74 → 75 taken 1 time.
257 for (int u = 0; u < lut_size; u++) {
2250 256 const double destu = (u - limits.middle_chroma) * uv_range_corr; // processpixel's minSat and maxSat is for 256 range
2251 256 int ushift = u << bits_per_pixel;
2252
2/2
✓ Branch 72 → 61 taken 65536 times.
✓ Branch 72 → 73 taken 256 times.
65792 for (int v = 0; v < lut_size; v++) {
2253 65536 const double destv = (v - limits.middle_chroma) * uv_range_corr;
2254 65536 int iSat = 0; // won't be used in MaskHS; interpolation is skipped since p==0:
2255
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);
2256
1/2
✓ Branch 62 → 63 taken 65536 times.
✗ Branch 62 → 67 not taken.
65536 if(pixelsize==1)
2257
2/2
✓ Branch 63 → 64 taken 8900 times.
✓ Branch 63 → 65 taken 56636 times.
65536 mapUV[ushift | v] = ppres ? mask_high : mask_low;
2258 else
2259 reinterpret_cast<uint16_t *>(mapUV)[ushift | v] = ppres ? mask_high : mask_low;
2260 }
2261 }
2262 } // end of lut calculation
2263 // #define MaskPointResizing
2264 #ifndef MaskPointResizing
2265
1/2
✓ Branch 75 → 76 taken 3 times.
✗ Branch 75 → 89 not taken.
3 vi.width >>= vi.GetPlaneWidthSubsampling(PLANAR_U);
2266
1/2
✓ Branch 76 → 77 taken 3 times.
✗ Branch 76 → 89 not taken.
3 vi.height >>= vi.GetPlaneHeightSubsampling(PLANAR_U);
2267 #endif
2268
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) {
2269 3 case 8: vi.pixel_type = VideoInfo::CS_Y8; break;
2270 case 10: vi.pixel_type = VideoInfo::CS_Y10; break;
2271 case 12: vi.pixel_type = VideoInfo::CS_Y12; break;
2272 case 14: vi.pixel_type = VideoInfo::CS_Y14; break;
2273 case 16: vi.pixel_type = VideoInfo::CS_Y16; break;
2274 case 32: vi.pixel_type = VideoInfo::CS_Y32; break;
2275 }
2276 11 }
2277
2278
2279
2280 5 PVideoFrame __stdcall MaskHS::GetFrame(int n, IScriptEnvironment* env)
2281 {
2282
1/2
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 101 not taken.
5 PVideoFrame src = child->GetFrame(n, env);
2283
1/2
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 99 not taken.
5 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
2284
2285
1/2
✓ Branch 6 → 7 taken 5 times.
✗ Branch 6 → 97 not taken.
5 uint8_t* dstp = dst->GetWritePtr();
2286
1/2
✓ Branch 8 → 9 taken 5 times.
✗ Branch 8 → 97 not taken.
5 int dst_pitch = dst->GetPitch();
2287
2288 // show mask
2289
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()) {
2290 const uint8_t* srcp = src->GetReadPtr();
2291 const int src_pitch = src->GetPitch();
2292 const int height = src->GetHeight();
2293
2294 #ifndef MaskPointResizing
2295 const int row_size = src->GetRowSize() >> 2;
2296
2297 for (int y = 0; y < height; y++) {
2298 for (int x = 0; x < row_size; x++) {
2299 dstp[x] = mapUV[((srcp[x * 4 + 1]) << 8) | srcp[x * 4 + 3]];
2300 }
2301 srcp += src_pitch;
2302 dstp += dst_pitch;
2303 }
2304 #else
2305 const int row_size = src->GetRowSize();
2306
2307 for (int y = 0; y < height; y++) {
2308 for (int xs = 0, xd = 0; xs < row_size; xs += 4, xd += 2) {
2309 const BYTE mapped = mapY[((srcp[xs + 1]) << 8) | srcp[xs + 3]];
2310 dstp[xd] = mapped;
2311 dstp[xd + 1] = mapped;
2312 }
2313 srcp += src_pitch;
2314 dstp += dst_pitch;
2315 }
2316 #endif
2317 }
2318
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()) {
2319
1/2
✓ Branch 32 → 33 taken 5 times.
✗ Branch 32 → 97 not taken.
5 const int srcu_pitch = src->GetPitch(PLANAR_U);
2320
1/2
✓ Branch 34 → 35 taken 5 times.
✗ Branch 34 → 97 not taken.
5 const uint8_t* srcpu = src->GetReadPtr(PLANAR_U);
2321
1/2
✓ Branch 36 → 37 taken 5 times.
✗ Branch 36 → 97 not taken.
5 const uint8_t* srcpv = src->GetReadPtr(PLANAR_V);
2322
1/2
✓ Branch 38 → 39 taken 5 times.
✗ Branch 38 → 97 not taken.
5 const int width = src->GetRowSize(PLANAR_U) / pixelsize;
2323
1/2
✓ Branch 40 → 41 taken 5 times.
✗ Branch 40 → 97 not taken.
5 const int heightu = src->GetHeight(PLANAR_U);
2324
2325 #ifndef MaskPointResizing
2326
2/2
✓ Branch 41 → 42 taken 3 times.
✓ Branch 41 → 77 taken 2 times.
5 if(realcalc_chroma) {
2327
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));
2328
1/2
✓ Branch 45 → 46 taken 3 times.
✗ Branch 45 → 56 not taken.
3 if(pixelsize == 1) {
2329
2/2
✓ Branch 55 → 47 taken 6 times.
✓ Branch 55 → 91 taken 3 times.
9 for (int y = 0; y < heightu; ++y) {
2330
2/2
✓ Branch 53 → 48 taken 36 times.
✓ Branch 53 → 54 taken 6 times.
42 for (int x = 0; x < width; ++x) {
2331 36 const double destu = srcpu[x] - limits.middle_chroma;
2332 36 const double destv = srcpv[x] - limits.middle_chroma;
2333 36 int iSat = 0; // won't be used in MaskHS; interpolation is skipped since p==0:
2334
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);
2335
2/2
✓ Branch 49 → 50 taken 16 times.
✓ Branch 49 → 51 taken 20 times.
36 dstp[x] = ppres ? mask_high : mask_low;
2336 }
2337 6 dstp += dst_pitch;
2338 6 srcpu += srcu_pitch;
2339 6 srcpv += srcu_pitch;
2340 }
2341 }
2342 else if (pixelsize == 2) {
2343 for (int y = 0; y < heightu; ++y) {
2344 for (int x = 0; x < width; ++x) {
2345 const double destu = (reinterpret_cast<const uint16_t *>(srcpu)[x] - limits.middle_chroma);
2346 const double destv = (reinterpret_cast<const uint16_t *>(srcpv)[x] - limits.middle_chroma);
2347 int iSat = 0; // won't be used in MaskHS; interpolation is skipped since p==0:
2348 bool ppres = ProcessPixel(destv * uv_range_corr, destu * uv_range_corr, dstartHue, dendHue, maxSat, minSat, 0.0, iSat);
2349 reinterpret_cast<uint16_t *>(dstp)[x] = ppres ? mask_high : mask_low;
2350 }
2351 dstp += dst_pitch;
2352 srcpu += srcu_pitch;
2353 srcpv += srcu_pitch;
2354 }
2355 } else { // pixelsize == 4
2356 for (int y = 0; y < heightu; ++y) {
2357 for (int x = 0; x < width; ++x) {
2358 const double destu = (reinterpret_cast<const float *>(srcpu)[x] - limits.middle_chroma_f);
2359 const double destv = (reinterpret_cast<const float *>(srcpv)[x] - limits.middle_chroma_f);
2360 int iSat = 0; // won't be used in MaskHS; interpolation is skipped since p==0:
2361 bool ppres = ProcessPixel(destv * uv_range_corr, destu * uv_range_corr, dstartHue, dendHue, maxSat, minSat, 0.0, iSat);
2362 reinterpret_cast<float *>(dstp)[x] = ppres ? mask_high_f : mask_low_f;
2363 }
2364 dstp += dst_pitch;
2365 srcpu += srcu_pitch;
2366 srcpv += srcu_pitch;
2367 }
2368 }
2369
2370 } else {
2371 // use LUT
2372
1/2
✓ Branch 77 → 78 taken 2 times.
✗ Branch 77 → 84 not taken.
2 if(pixelsize==1) {
2373
2/2
✓ Branch 83 → 79 taken 4 times.
✓ Branch 83 → 91 taken 2 times.
6 for (int y = 0; y < heightu; ++y) {
2374
2/2
✓ Branch 81 → 80 taken 28 times.
✓ Branch 81 → 82 taken 4 times.
32 for (int x = 0; x < width; ++x) {
2375 28 dstp[x] = mapUV[((srcpu[x]) << 8) | srcpv[x]];
2376 }
2377 4 dstp += dst_pitch;
2378 4 srcpu += srcu_pitch;
2379 4 srcpv += srcu_pitch;
2380 }
2381 }
2382 else if (pixelsize == 2) {
2383 for (int y = 0; y < heightu; ++y) {
2384 for (int x = 0; x < width; ++x) {
2385 reinterpret_cast<uint16_t *>(dstp)[x] =
2386 reinterpret_cast<uint16_t *>(mapUV)[((reinterpret_cast<const uint16_t *>(srcpu)[x]) << bits_per_pixel) | reinterpret_cast<const uint16_t *>(srcpv)[x]];
2387 }
2388 dstp += dst_pitch;
2389 srcpu += srcu_pitch;
2390 srcpv += srcu_pitch;
2391 }
2392 } // no lut for float (and for 14-16 bit)
2393 }
2394 #else
2395 const int swidth = child->GetVideoInfo().GetPlaneWidthSubsampling(PLANAR_U);
2396 const int sheight = child->GetVideoInfo().GetPlaneHeightSubsampling(PLANAR_U);
2397 const int sw = 1 << swidth;
2398 const int sh = 1 << sheight;
2399
2400 const int dpitch = dst_pitch << sheight;
2401 for (int y = 0; y < heightu; ++y) {
2402 for (int x = 0; x < row_sizeu; ++x) {
2403 const BYTE mapped = mapY[((srcpu[x]) << 8) | srcpv[x]];
2404 const int sx = x << swidth;
2405
2406 for (int lumv = 0; lumv < sh; ++lumv) {
2407 const int sy = lumv*dst_pitch + sx;
2408
2409 for (int lumh = 0; lumh < sw; ++lumh) {
2410 dstp[sy + lumh] = mapped;
2411 }
2412 }
2413 }
2414 dstp += dpitch;
2415 srcpu += srcu_pitch;
2416 srcpv += srcu_pitch;
2417 }
2418 #endif
2419 }
2420 5 return dst;
2421 5 }
2422
2423
2424
2425 AVSValue __cdecl MaskHS::Create(AVSValue args, void* , IScriptEnvironment* env)
2426 {
2427 return new MaskHS(args[0].AsClip(),
2428 args[1].AsDblDef(0.0), // startHue
2429 args[2].AsDblDef(360.0), // endHue
2430 args[3].AsDblDef(150.0), // maxSat
2431 args[4].AsDblDef(0.0), // minSat
2432 args[5].AsBool(false), // coring
2433 args[6].AsBool(false), // realcalc
2434 env);
2435 }
2436
2437