GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 24.7% 515 / 0 / 2084
Functions: 33.3% 17 / 0 / 51
Branches: 20.3% 452 / 0 / 2225

filters/histogram.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 // FIXME: in general: how to display 32 bit floats?
36 // Do we have to assume it as if it is used after a limited -> full scale conversion? (preferred - everywhere!)
37 // Or with values simply: pixel_8bit / 255.0?
38 // Latter logic converts U=240 to (240-128)/255 instead of (240-128)/226 (=0.5)
39 // and Y=235 to 235/255 instead of (235-16)/219 (=1.0)
40
41 #include "histogram.h"
42 #include "../core/info.h"
43 #include "../core/internal.h"
44 #include "../convert/convert_planar.h"
45 #include "../convert/convert_audio.h"
46 #include "../convert/convert_helper.h"
47 #include "../convert/convert_matrix.h"
48 #include "colorbars_const.h"
49
50 #ifdef AVS_WINDOWS
51 #include <avs/win.h>
52 #else
53 #include <avs/posix.h>
54 #endif
55
56 #include <memory>
57 #include <avs/minmax.h>
58 #include <cstdio>
59 #include <cmath>
60 #include <stdint.h>
61 #include <vector>
62
63
64 constexpr double PI = 3.14159265358979323846;
65 // until c++20 <numbers> std::numbers::pi
66
67 /********************************************************************
68 ***** Declare index of new filters for Avisynth's filter engine *****
69 ********************************************************************/
70 extern const AVSFunction Histogram_filters[] = {
71 { "Histogram", BUILTIN_FUNC_PREFIX, "c[mode]s[factor]f[bits]i[keepsource]b[markers]b[matrix]s[graticule]s[targets]b[axes]b[iq]b[iq_lines]b[circle]b[targets100]b", Histogram::Create },
72 { 0 }
73 };
74
75 /***********************************
76 ******* Histogram Filter ******
77 **********************************/
78
79 11 Histogram::Histogram(PClip _child, Mode _mode, AVSValue _option, int _show_bits, bool _keepsource, bool _markers, const char* _matrix_name, histogram_color2_params _color2_params, IScriptEnvironment* env)
80
4/8
✓ Branch 2 → 3 taken 11 times.
✗ Branch 2 → 151 not taken.
✓ Branch 3 → 4 taken 11 times.
✗ Branch 3 → 149 not taken.
✓ Branch 5 → 6 taken 11 times.
✗ Branch 5 → 173 not taken.
✓ Branch 6 → 7 taken 11 times.
✗ Branch 6 → 171 not taken.
11 : GenericVideoFilter(_child), mode(_mode), option(_option), show_bits(_show_bits), keepsource(_keepsource), markers(_markers), color2_params(_color2_params)
81 {
82 11 bool optionValid = false;
83
84
1/2
✓ Branch 8 → 9 taken 11 times.
✗ Branch 8 → 166 not taken.
11 pixelsize = vi.ComponentSize();
85
1/2
✓ Branch 9 → 10 taken 11 times.
✗ Branch 9 → 166 not taken.
11 bits_per_pixel = vi.BitsPerComponent();
86
87
4/4
✓ Branch 10 → 11 taken 10 times.
✓ Branch 10 → 12 taken 1 time.
✓ Branch 11 → 12 taken 1 time.
✓ Branch 11 → 13 taken 9 times.
11 if(show_bits < 8 || show_bits>12)
88
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 166 taken 2 times.
2 env->ThrowError("Histogram: bits parameter can only be 8, 9 .. 12");
89
90 // until all histogram is ported
91
2/4
✓ Branch 13 → 14 taken 9 times.
✗ Branch 13 → 15 not taken.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 9 times.
9 bool non8bit = show_bits != 8 || bits_per_pixel != 8;
92
93
1/12
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 24 taken 9 times.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 24 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 24 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 24 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 24 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 24 not taken.
9 if (non8bit && mode != ModeClassic && mode != ModeLevels && mode != ModeColor && mode != ModeColor2 && mode != ModeLuma)
94 {
95 env->ThrowError("Histogram: this histogram type is available only for 8 bit formats and parameters");
96 }
97
98 // Obtain matrix (for YUV) and video range
99
1/2
✓ Branch 25 → 26 taken 9 times.
✗ Branch 25 → 166 not taken.
9 auto frame0 = child->GetFrame(0, env);
100
1/2
✓ Branch 26 → 27 taken 9 times.
✗ Branch 26 → 164 not taken.
9 const AVSMap* props = env->getFramePropsRO(frame0);
101 // default YUV matrix AVS_MATRIX_ST170_M (BT 601)
102
1/2
✓ Branch 27 → 28 taken 9 times.
✗ Branch 27 → 164 not taken.
9 const bool rgb_in = vi.IsRGB();
103
1/2
✓ Branch 28 → 29 taken 9 times.
✗ Branch 28 → 164 not taken.
9 matrix_parse_merge_with_props(rgb_in, rgb_in /* rgb_out n/a */ , _matrix_name, props, theMatrix, theColorRange, theOutColorRange, env);
104
105 // theColorRange is either inherited
106 // - from defaults (RGB full YUV limited) or
107 // - _ColorRange frame property or
108 // - manual override from "matrix" param ":f" or ":l" designator
109 // theOutColorRange is only used in yuv-rgb converters
110 9 full_range = theColorRange == ColorRange_Compat_e::AVS_COLORRANGE_FULL;
111 // Full range or limited?
112 // VectorScope modes (color, color2) require full range to
113 // - properly place the color boxes
114 // - When the histogram's virtual bit-size is different from the real video bit-depth
115 // then video-bit depth must be converted to the histogram's bit-depth either by
116 // limited (shift) or full range (stretch) method.
117
118 9 const int shift = 13; // not used here, we only get the floating point matrix
119 // use matrix coeffs in color/color2 for positioning RGB color boxes for the actual YUV matrix.
120 // Detected input color range is theColorRange, detected matrix is theMatrix.
121
2/4
✓ Branch 29 → 30 taken 9 times.
✗ Branch 29 → 164 not taken.
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 9 times.
9 if (!do_BuildMatrix_Rgb2Yuv(theMatrix, theColorRange, theOutColorRange, shift, 32, /*ref*/matrix))
122 env->ThrowError("Histogram: Unsupported matrix.");
123
124 9 origwidth = vi.width;
125 9 origheight = vi.height;
126
127
2/2
✓ Branch 32 → 33 taken 2 times.
✓ Branch 32 → 45 taken 7 times.
9 if (mode == ModeClassic) {
128
3/10
✓ Branch 33 → 34 taken 2 times.
✗ Branch 33 → 164 not taken.
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 38 taken 2 times.
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 164 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 38 not taken.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 2 times.
2 if (!vi.IsYUV() && !vi.IsYUVA())
129 env->ThrowError("Histogram: YUV(A) data only");
130
2/2
✓ Branch 41 → 42 taken 1 time.
✓ Branch 41 → 43 taken 1 time.
2 if(keepsource)
131 1 vi.width += (1 << show_bits);
132 else
133 1 vi.width = (1 << show_bits);
134
1/2
✓ Branch 44 → 45 taken 2 times.
✗ Branch 44 → 164 not taken.
2 ClassicLUTInit();
135 }
136
137
2/2
✓ Branch 45 → 46 taken 2 times.
✓ Branch 45 → 58 taken 7 times.
9 if (mode == ModeLevels) {
138
2/4
✓ Branch 46 → 47 taken 2 times.
✗ Branch 46 → 164 not taken.
✗ Branch 47 → 48 not taken.
✓ Branch 47 → 49 taken 2 times.
2 if (!vi.IsPlanar()) {
139 env->ThrowError("Histogram: Levels mode only available in PLANAR.");
140 }
141
1/2
✓ Branch 49 → 50 taken 2 times.
✗ Branch 49 → 164 not taken.
2 optionValid = option.IsFloat();
142
1/2
✓ Branch 50 → 51 taken 2 times.
✗ Branch 50 → 164 not taken.
2 const double factor = option.AsDblDef(100.0); // Population limit % factor
143
2/4
✓ Branch 51 → 52 taken 2 times.
✗ Branch 51 → 53 not taken.
✗ Branch 52 → 53 not taken.
✓ Branch 52 → 54 taken 2 times.
2 if (factor < 0.0 || factor > 100.0) {
144 env->ThrowError("Histogram: Levels population clamping must be between 0 and 100%");
145 }
146 // put diagram on the right side
147
1/2
✓ Branch 54 → 55 taken 2 times.
✗ Branch 54 → 57 not taken.
2 if (keepsource) {
148 2 vi.width += (1 << show_bits); // 256 for 8 bit
149 2 vi.height = max(256, vi.height);
150 }
151 else { // or keep it alone
152 vi.width = (1 << show_bits);
153 vi.height = 256; // only 224+1 (3*64 + 2*16 + 1) is used
154 }
155 }
156
157
4/4
✓ Branch 58 → 59 taken 8 times.
✓ Branch 58 → 60 taken 1 time.
✓ Branch 59 → 60 taken 2 times.
✓ Branch 59 → 77 taken 6 times.
9 if (mode == ModeColor || mode == ModeColor2) {
158
2/4
✓ Branch 60 → 61 taken 3 times.
✗ Branch 60 → 164 not taken.
✗ Branch 61 → 62 not taken.
✓ Branch 61 → 63 taken 3 times.
3 if (vi.IsRGB()) {
159 env->ThrowError("Histogram: VectorScope modes (color, color2) are not available in RGB.");
160 }
161
2/4
✓ Branch 63 → 64 taken 3 times.
✗ Branch 63 → 164 not taken.
✗ Branch 64 → 65 not taken.
✓ Branch 64 → 66 taken 3 times.
3 if (!vi.IsPlanar()) {
162 env->ThrowError("Histogram: VectorScope modes (color, color2) only available in PLANAR.");
163 }
164
3/4
✓ Branch 66 → 67 taken 3 times.
✗ Branch 66 → 164 not taken.
✓ Branch 67 → 68 taken 1 time.
✓ Branch 67 → 69 taken 2 times.
3 if (vi.IsY()) {
165
1/2
✗ Branch 68 → 69 not taken.
✓ Branch 68 → 164 taken 1 time.
1 env->ThrowError("Histogram: VectorScope modes (color, color2) are not available in greyscale.");
166 }
167 // put diagram on the right side
168
1/2
✗ Branch 69 → 70 not taken.
✓ Branch 69 → 72 taken 2 times.
2 if (keepsource) {
169 vi.width += (1 << show_bits); // 256 for 8 bit
170 vi.height = max(1 << show_bits, vi.height);
171 }
172 else {
173 2 vi.width = (1 << show_bits); // 256 for 8 bit
174 2 vi.height = 1 << show_bits;
175 }
176
177 // for params.circle == true
178 // precalculate 15 degree marker dots
179
1/2
✗ Branch 73 → 74 not taken.
✓ Branch 73 → 77 taken 2 times.
2 if (color2_params.circle) {
180 const int half = (1 << (show_bits - 1)) - 1; // 127
181 // dots are placed somewhat inside to the colorful circle, which is thicker for higher show_bits
182 color2_innerF = 124.9; // .9 is for better visuals in subsampled mode
183 int R = (int)(1 + color2_innerF * (1 << (show_bits - 8)) + 0.5); // 126 for 8 bits
184
185 for (int y = 0; y < 24; y++) { // just inside the big circle
186 deg15c[y] = (int)(R * cos(y * PI / 12.) + 0.5) + half;
187 deg15s[y] = (int)(-R * sin(y * PI / 12.) + 0.5) + half;
188 }
189 }
190 }
191
192
7/12
✓ Branch 77 → 78 taken 1 time.
✓ Branch 77 → 83 taken 7 times.
✓ Branch 78 → 79 taken 1 time.
✗ Branch 78 → 164 not taken.
✓ Branch 79 → 80 taken 1 time.
✗ Branch 79 → 83 not taken.
✓ Branch 80 → 81 taken 1 time.
✗ Branch 80 → 164 not taken.
✗ Branch 81 → 82 not taken.
✓ Branch 81 → 83 taken 1 time.
✗ Branch 84 → 85 not taken.
✓ Branch 84 → 86 taken 8 times.
8 if (mode == ModeLuma && !vi.IsYUV() && !vi.IsYUVA()) {
193 env->ThrowError("Histogram: Luma mode only available in YUV(A).");
194 }
195
196
3/6
✓ Branch 86 → 87 taken 8 times.
✗ Branch 86 → 89 not taken.
✓ Branch 87 → 88 taken 8 times.
✗ Branch 87 → 89 not taken.
✗ Branch 88 → 89 not taken.
✓ Branch 88 → 122 taken 8 times.
8 if ((mode == ModeStereoY8)||(mode == ModeStereo)||(mode == ModeOverlay)) {
197
198 child->SetCacheHints(CACHE_AUDIO,4096*1024);
199
200 if (!vi.HasVideo()) {
201 mode = ModeStereo; // force mode to ModeStereo.
202 vi.fps_numerator = 25;
203 vi.fps_denominator = 1;
204 vi.num_frames = vi.FramesFromAudioSamples(vi.num_audio_samples);
205 }
206 if (mode == ModeOverlay) {
207 if (keepsource) {
208 vi.height = max(512, vi.height);
209 vi.width = max(512, vi.width);
210 }
211 else {
212 vi.height = 512;
213 vi.width = 512;
214 }
215 if (vi.IsRGB()) {
216 env->ThrowError("Histogram: StereoOverlay mode is not available in RGB.");
217 }
218 if (!vi.IsPlanar()) {
219 env->ThrowError("Histogram: StereoOverlay only available in Y or YUV(A).");
220 }
221 } else if (mode == ModeStereoY8) {
222 vi.pixel_type = VideoInfo::CS_Y8;
223 vi.height = 512;
224 vi.width = 512;
225 } else {
226 vi.pixel_type = VideoInfo::CS_YV12;
227 vi.height = 512;
228 vi.width = 512;
229 }
230 if (!vi.HasAudio()) {
231 env->ThrowError("Histogram: Stereo mode requires samples!");
232 }
233 if (vi.AudioChannels() != 2) {
234 env->ThrowError("Histogram: Stereo mode only works on two audio channels.");
235 }
236
237 aud_clip = ConvertAudio::Create(child,SAMPLE_INT16,SAMPLE_INT16);
238 }
239
240
2/2
✓ Branch 122 → 123 taken 1 time.
✓ Branch 122 → 140 taken 7 times.
8 if (mode == ModeAudioLevels) {
241
1/2
✓ Branch 124 → 125 taken 1 time.
✗ Branch 124 → 164 not taken.
1 child->SetCacheHints(CACHE_AUDIO, 4096*1024);
242
2/4
✓ Branch 125 → 126 taken 1 time.
✗ Branch 125 → 164 not taken.
✗ Branch 126 → 127 not taken.
✓ Branch 126 → 128 taken 1 time.
1 if (vi.IsRGB()) {
243 env->ThrowError("Histogram: Audiolevels mode is not available in RGB.");
244 }
245
2/4
✓ Branch 128 → 129 taken 1 time.
✗ Branch 128 → 164 not taken.
✗ Branch 129 → 130 not taken.
✓ Branch 129 → 131 taken 1 time.
1 if (!vi.IsPlanar()) {
246 env->ThrowError("Histogram: Audiolevels mode only available in planar YUV.");
247 }
248
2/4
✓ Branch 131 → 132 taken 1 time.
✗ Branch 131 → 164 not taken.
✗ Branch 132 → 133 not taken.
✓ Branch 132 → 134 taken 1 time.
1 if (vi.IsY8()) {
249 env->ThrowError("Histogram: AudioLevels mode not available in Y8.");
250 }
251
252
3/6
✓ Branch 134 → 135 taken 1 time.
✗ Branch 134 → 162 not taken.
✓ Branch 135 → 136 taken 1 time.
✗ Branch 135 → 160 not taken.
✓ Branch 136 → 137 taken 1 time.
✗ Branch 136 → 158 not taken.
1 aud_clip = ConvertAudio::Create(child, SAMPLE_INT16, SAMPLE_INT16);
253 }
254
255
5/8
✓ Branch 140 → 141 taken 6 times.
✓ Branch 140 → 144 taken 2 times.
✓ Branch 141 → 142 taken 6 times.
✗ Branch 141 → 164 not taken.
✗ Branch 142 → 143 not taken.
✓ Branch 142 → 144 taken 6 times.
✗ Branch 145 → 146 not taken.
✓ Branch 145 → 147 taken 8 times.
8 if (!optionValid && option.Defined())
256 env->ThrowError("Histogram: Unknown optional value.");
257 21 }
258
259 7 PVideoFrame __stdcall Histogram::GetFrame(int n, IScriptEnvironment* env)
260 {
261
5/9
✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 4 taken 1 time.
✓ Branch 2 → 5 taken 1 time.
✓ Branch 2 → 6 taken 1 time.
✓ Branch 2 → 7 taken 1 time.
✗ Branch 2 → 8 not taken.
✗ Branch 2 → 9 not taken.
✗ Branch 2 → 10 not taken.
✗ Branch 2 → 11 not taken.
7 switch (mode) {
262 3 case ModeClassic:
263 3 return DrawModeClassic(n, env);
264 1 case ModeLevels:
265 1 return DrawModeLevels(n, env);
266 1 case ModeColor:
267 1 return DrawModeColor(n, env);
268 1 case ModeColor2:
269 1 return DrawModeColor2(n, env);
270 1 case ModeLuma:
271 1 return DrawModeLuma(n, env);
272 case ModeStereoY8:
273 case ModeStereo:
274 return DrawModeStereo(n, env);
275 case ModeOverlay:
276 return DrawModeOverlay(n, env);
277 case ModeAudioLevels:
278 return DrawModeAudioLevels(n, env);
279 }
280 return DrawModeClassic(n, env);
281 }
282
283 inline void MixLuma(BYTE &src, int value, int alpha) {
284 src = src + BYTE(((value - (int)src) * alpha) >> 8);
285 }
286
287 PVideoFrame Histogram::DrawModeAudioLevels(int n, IScriptEnvironment* env) {
288 PVideoFrame src = child->GetFrame(n, env);
289 env->MakeWritable(&src);
290 const int w = src->GetRowSize();
291 const int channels = vi.AudioChannels();
292
293 constexpr int TEXT_HEIGHT = 20; // for DrawString
294 int bar_w = 60; // Must be divideable by 4 (for subsampling)
295 int total_width = (1+channels*2)*bar_w; // Total width in pixels.
296
297 if (total_width > w) {
298 bar_w = ((w / (1+channels*2)) / 4)* 4;
299 }
300 total_width = (1+channels*2)*bar_w; // Total width in pixels.
301 int bar_h = vi.height;
302
303 // Get audio for current frame.
304 const int64_t start = vi.AudioSamplesFromFrames(n);
305 const int count = (int)(vi.AudioSamplesFromFrames(1));
306 signed short* samples = static_cast<signed short*>(_alloca(sizeof(signed short)* count * channels));
307
308 aud_clip->GetAudio(samples, max((int64_t)0ll,start), count, env);
309
310 // Find maximum volume and rms.
311 int* channel_max = static_cast<int*>(_alloca(channels * sizeof(int)));
312 int64_t* channel_rms = static_cast<int64_t*>(_alloca(channels * sizeof(int64_t)));;
313
314 const int c = count*channels;
315 for (int ch = 0; ch<channels; ch++) {
316 int max_vol = 0;
317 int64_t rms_vol = 0;
318
319 for (int i = ch; i < c; i += channels) {
320 int sample = samples[i];
321 sample *= sample;
322 rms_vol += sample;
323 max_vol = max(max_vol, sample);
324 }
325 channel_max[ch] = max_vol;
326 channel_rms[ch] = rms_vol;
327 }
328
329 // Draw bars
330 BYTE* srcpY = src->GetWritePtr(PLANAR_Y);
331 int Ypitch = src->GetPitch(PLANAR_Y);
332 BYTE* srcpU = src->GetWritePtr(PLANAR_U);
333 BYTE* srcpV = src->GetWritePtr(PLANAR_V);
334 int UVpitch = src->GetPitch(PLANAR_U);
335 int xSubS = vi.GetPlaneWidthSubsampling(PLANAR_U);
336 int ySubS = vi.GetPlaneHeightSubsampling(PLANAR_U);
337
338 // Draw Dotted lines
339 const int lines = 16; // Line every 6dB (96/6)
340 int lines_y[lines];
341 float line_every = (float)bar_h / (float)lines;
342 char text[32];
343 for (int i=0; i<lines; i++) {
344 lines_y[i] = (int)(line_every*i);
345 if (!(i&1)) {
346 snprintf(text, sizeof(text), "%3ddB", -i*6);
347 DrawStringPlanar(vi, src, 0, i ? lines_y[i] : TEXT_HEIGHT / 2, text);
348 }
349 }
350 for (int x=bar_w-16; x<total_width-bar_w+16; x++) {
351 if (!(x&12)) {
352 for (int i=0; i<lines; i++) {
353 srcpY[x+lines_y[i]*Ypitch] = 200;
354 }
355 }
356 }
357
358 for (int ch = 0; ch<channels; ch++) {
359 int max = channel_max[ch];
360 double ch_db = 96;
361 if (max > 0) {
362 ch_db = -8.685889638/2.0 * log((double)max/(32768.0*32768.0));
363 }
364
365 int64_t rms = channel_rms[ch] / count;
366 double ch_rms = 96;
367 if (rms > 0) {
368 ch_rms = -8.685889638/2.0 * log((double)rms/(32768.0*32768.0));
369 }
370
371 int x_pos = ((ch*2)+1)*bar_w+8;
372 int x_end = x_pos+bar_w-8;
373 int y_pos = (int)(((double)bar_h*ch_db) / 96.0);
374 int y_mid = (int)(((double)bar_h*ch_rms) / 96.0);
375 int y_end = src->GetHeight(PLANAR_Y);
376 // Luma Red Blue
377 int y_val = (max>=32767*32767) ? 78 : 90;
378 int a_val = (max>=32767*32767) ? 96 : 128;
379 for (int y = y_pos; y<y_mid; y++) {
380 for (int x = x_pos; x < x_end; x++) {
381 MixLuma(srcpY[x+y*Ypitch], y_val, a_val);
382 }
383 } // Yellow Green
384 y_val = (max>=32767*32767) ? 216 : 137;
385 a_val = (max>=32767*32767) ? 160 : 128;
386 for (int y = y_mid; y<y_end; y++) {
387 for (int x = x_pos; x < x_end; x++) {
388 MixLuma(srcpY[x+y*Ypitch], y_val, a_val);
389 }
390 }
391 // Chroma
392 x_pos >>= xSubS;
393 x_end >>= xSubS;
394 y_pos >>= ySubS;
395 y_mid >>= ySubS;
396 y_end = src->GetHeight(PLANAR_U);//Red Blue
397 BYTE u_val = (max>=32767*32767) ? 92 : 212;
398 BYTE v_val = (max>=32767*32767) ? 233 : 114;
399 for (int y = y_pos; y<y_mid; y++) {
400 for (int x = x_pos; x < x_end; x++) {
401 srcpU[x+y*UVpitch] = u_val;
402 srcpV[x+y*UVpitch] = v_val;
403 }
404 } // Yellow Green
405 u_val = (max>=32767*32767) ? 44 : 58;
406 v_val = (max>=32767*32767) ? 142 : 40;
407 for (int y = y_mid; y<y_end; y++) {
408 for (int x = x_pos; x < x_end; x++) {
409 srcpU[x+y*UVpitch] = u_val;
410 srcpV[x+y*UVpitch] = v_val;
411 }
412 }
413 // Draw text
414 snprintf(text, sizeof(text), "%6.2fdB", (float)-ch_db);
415 DrawStringPlanar(vi, src, ((ch*2)+1)*bar_w, vi.height- 2 * TEXT_HEIGHT + TEXT_HEIGHT / 2, text);
416 snprintf(text, sizeof(text), "%6.2fdB", (float)-ch_rms);
417 DrawStringPlanar(vi, src, ((ch*2)+1)*bar_w, vi.height- 1 * TEXT_HEIGHT + TEXT_HEIGHT / 2, text);
418
419 }
420
421 return src;
422 }
423
424 PVideoFrame Histogram::DrawModeOverlay(int n, IScriptEnvironment* env) {
425 PVideoFrame src = child->GetFrame(n, env);
426 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
427
428 int64_t start = vi.AudioSamplesFromFrames(n);
429 int64_t end = vi.AudioSamplesFromFrames(n+1);
430 int64_t count = end-start;
431 signed short* samples = static_cast<signed short*>(
432 env->Allocate((int)count * vi.AudioChannels() * sizeof(unsigned short), 8, AVS_POOLED_ALLOC)
433 );
434 if (!samples) {
435 env->ThrowError("Histogram: Could not reserve memory.");
436 }
437
438 int h = dst->GetHeight();
439 int imgSize = h*dst->GetPitch();
440 BYTE* dstp = dst->GetWritePtr();
441 int p = dst->GetPitch(PLANAR_Y);
442
443 if ((src->GetHeight()<dst->GetHeight()) || (src->GetRowSize() < dst->GetRowSize())) {
444 memset(dstp, 16, imgSize);
445 int imgSizeU = dst->GetHeight(PLANAR_U) * dst->GetPitch(PLANAR_U);
446 if (imgSizeU) {
447 memset(dst->GetWritePtr(PLANAR_U), 128, imgSizeU);
448 memset(dst->GetWritePtr(PLANAR_V), 128, imgSizeU);
449 }
450 }
451
452 env->BitBlt(dstp, dst->GetPitch(), src->GetReadPtr(), src->GetPitch(), src->GetRowSize(), src->GetHeight());
453 env->BitBlt(dst->GetWritePtr(PLANAR_U), dst->GetPitch(PLANAR_U), src->GetReadPtr(PLANAR_U), src->GetPitch(PLANAR_U), src->GetRowSize(PLANAR_U), src->GetHeight(PLANAR_U));
454 env->BitBlt(dst->GetWritePtr(PLANAR_V), dst->GetPitch(PLANAR_V), src->GetReadPtr(PLANAR_V), src->GetPitch(PLANAR_V), src->GetRowSize(PLANAR_V), src->GetHeight(PLANAR_V));
455
456 BYTE* _dstp = dstp;
457 for (int iY = 0; iY<512; iY++) {
458 for (int iX = 0; iX<512; iX++) {
459 _dstp[iX] >>= 1;
460 }
461 _dstp+=p;
462 }
463
464 aud_clip->GetAudio(samples, max((int64_t)0ll,start), count, env);
465
466 int c = (int)count;
467 for (int i=1; i < c;i++) {
468 int l1 = samples[i*2-2];
469 int r1 = samples[i*2-1];
470 int l2 = samples[i*2];
471 int r2 = samples[i*2+1];
472 for (int s = 0 ; s < 8; s++) { // 8 times supersampling (linear)
473 int l = (l1*s) + (l2*(8-s));
474 int r = (r1*s) + (r2*(8-s));
475 int y = 256+((l+r)>>11);
476 int x = 256+((l-r)>>11);
477 BYTE v = dstp[x+y*p]+48;
478 dstp[x+y*p] = min(v,(BYTE)235);
479 }
480 }
481
482 int y_off = p*256;
483 for (int x = 0; x < 512; x+=16)
484 dstp[y_off + x] = (dstp[y_off + x] > 127) ? 16 : 235;
485
486 for (int y = 0; y < 512;y+=16)
487 dstp[y*p+256] = (dstp[y*p+256]>127) ? 16 : 235 ;
488
489 env->Free(samples);
490 return dst;
491 }
492
493
494 PVideoFrame Histogram::DrawModeStereo(int n, IScriptEnvironment* env) {
495 PVideoFrame src = env->NewVideoFrame(vi);
496 int64_t start = vi.AudioSamplesFromFrames(n);
497 int64_t end = vi.AudioSamplesFromFrames(n+1);
498 int64_t count = end-start;
499 signed short* samples = static_cast<signed short*>(
500 env->Allocate((int)count * vi.AudioChannels() * sizeof(unsigned short), 8, AVS_POOLED_ALLOC)
501 );
502 if (!samples) {
503 env->ThrowError("Histogram: Could not reserve memory.");
504 }
505
506 int h = src->GetHeight();
507 int imgSize = h*src->GetPitch();
508 BYTE* srcp = src->GetWritePtr();
509 memset(srcp, 16, imgSize);
510 int p = src->GetPitch();
511
512 aud_clip->GetAudio(samples, max((int64_t)0ll,start), count, env);
513
514 int c = (int)count;
515 for (int i=1; i < c;i++) {
516 int l1 = samples[i*2-2];
517 int r1 = samples[i*2-1];
518 int l2 = samples[i*2];
519 int r2 = samples[i*2+1];
520 for (int s = 0 ; s < 8; s++) { // 8 times supersampling (linear)
521 int l = (l1*s) + (l2*(8-s));
522 int r = (r1*s) + (r2*(8-s));
523 int y = 256+((l+r)>>11);
524 int x = 256+((l-r)>>11);
525 BYTE v = srcp[x+y*512]+48;
526 srcp[x+y*512] = min(v, (BYTE)235);
527 }
528 }
529
530 int y_off = p*256;
531 for (int x = 0; x < 512; x+=16)
532 srcp[y_off + x] = (srcp[y_off + x] > 127) ? 16 : 235;
533
534 for (int y = 0; y < 512;y+=16)
535 srcp[y*p+256] = (srcp[y*p+256]>127) ? 16 : 235 ;
536
537 if (vi.IsYV12()) {
538 srcp = src->GetWritePtr(PLANAR_U);
539 imgSize = src->GetHeight(PLANAR_U) * src->GetPitch(PLANAR_U);
540 memset(srcp, 128, imgSize);
541 srcp = src->GetWritePtr(PLANAR_V);
542 memset(srcp, 128, imgSize);
543 }
544
545 env->Free(samples);
546 return src;
547 }
548
549
550 1 PVideoFrame Histogram::DrawModeLuma(int n, IScriptEnvironment* env) {
551 // amplify luminance.
552 // In this mode a 1 pixel luminance difference (8 bits world) will show as
553 // a 16 pixel luminance, thus seriously enhancing small flaws
554 1 PVideoFrame src = child->GetFrame(n, env);
555
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 84 not taken.
1 env->MakeWritable(&src);
556
1/2
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 84 not taken.
1 const int h = src->GetHeight();
557
1/2
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 84 not taken.
1 BYTE* srcp = src->GetWritePtr();
558
2/4
✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 84 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 19 taken 1 time.
1 if (vi.IsYUY2()) {
559 int imgsize = h * src->GetPitch();
560 for (int i=0; i<imgsize; i+=2) {
561 int p = srcp[i];
562 p<<=4;
563 srcp[i+1] = 128;
564 srcp[i] = BYTE((p&256) ? (255-(p&0xff)) : p&0xff);
565 }
566 } else {
567 1 const int w = vi.width;
568
1/2
✓ Branch 20 → 21 taken 1 time.
✗ Branch 20 → 84 not taken.
1 const int pitch = src->GetPitch();
569
1/2
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 31 not taken.
1 if (bits_per_pixel == 8) {
570
2/2
✓ Branch 30 → 23 taken 4 times.
✓ Branch 30 → 50 taken 1 time.
5 for (int y = 0; y < h; y++) {
571
2/2
✓ Branch 28 → 24 taken 16 times.
✓ Branch 28 → 29 taken 4 times.
20 for (int x = 0; x < w; x++) {
572 16 const int pixel = srcp[x] << 4; // *16
573
2/2
✓ Branch 24 → 25 taken 8 times.
✓ Branch 24 → 26 taken 8 times.
16 srcp[x] = BYTE((pixel & 256) ? (255 - (pixel & 0xff)) : pixel & 0xff);
574 }
575 4 srcp += pitch;
576 }
577 }
578 else if (bits_per_pixel <= 16) {
579 const int overlimit = (1 << bits_per_pixel);
580 const int max_pixel_value = (1 << bits_per_pixel) - 1;
581 for (int y = 0; y < h; y++) {
582 for (int x = 0; x < w; x++) {
583 const int pixel = reinterpret_cast<uint16_t*>(srcp)[x] << 4;
584 reinterpret_cast<uint16_t*>(srcp)[x] = (uint16_t)((pixel & overlimit) ? (max_pixel_value - (pixel & max_pixel_value)) : pixel & max_pixel_value);
585 }
586 srcp += pitch;
587 }
588 }
589 else {
590 // 32 bit float
591 // just simulated by converting to 8 bits
592 for (int y = 0; y < h; y++) {
593 for (int x = 0; x < w; x++) {
594 const float pixel_f = reinterpret_cast<float*>(srcp)[x];
595 const int pixel_i = (int)(pixel_f * 255.0f + 0.5f);
596 const int pixel = pixel_i << 4; // *16
597 int pixel_out = BYTE((pixel & 256) ? (255 - (pixel & 0xff)) : pixel & 0xff);
598 const float pixel_out_f = pixel_out / 255.0f;
599 reinterpret_cast<float*>(srcp)[x] = pixel_out_f;
600 }
601 srcp += pitch;
602 }
603 }
604
605
2/4
✓ Branch 50 → 51 taken 1 time.
✗ Branch 50 → 84 not taken.
✓ Branch 51 → 52 taken 1 time.
✗ Branch 51 → 82 not taken.
1 if (vi.NumComponents() >= 3) {
606
1/2
✓ Branch 53 → 54 taken 1 time.
✗ Branch 53 → 84 not taken.
1 auto dstp_u = src->GetWritePtr(PLANAR_U);
607
1/2
✓ Branch 55 → 56 taken 1 time.
✗ Branch 55 → 84 not taken.
1 auto dstp_v = src->GetWritePtr(PLANAR_V);
608
1/2
✓ Branch 57 → 58 taken 1 time.
✗ Branch 57 → 84 not taken.
1 auto height_uv = src->GetHeight(PLANAR_U);
609
1/2
✓ Branch 59 → 60 taken 1 time.
✗ Branch 59 → 84 not taken.
1 auto rowsize_uv = src->GetRowSize(PLANAR_U);
610
1/2
✓ Branch 61 → 62 taken 1 time.
✗ Branch 61 → 84 not taken.
1 auto pitch_uv = src->GetPitch(PLANAR_U);
611
1/2
✓ Branch 62 → 63 taken 1 time.
✗ Branch 62 → 64 not taken.
1 if (bits_per_pixel == 8)
612
1/2
✓ Branch 63 → 67 taken 1 time.
✗ Branch 63 → 84 not taken.
1 fill_chroma<uint8_t>(dstp_u, dstp_v, height_uv, rowsize_uv, pitch_uv, 128);
613 else if (bits_per_pixel <= 16)
614 fill_chroma<uint16_t>(dstp_u, dstp_v, height_uv, rowsize_uv, pitch_uv, 128 << (bits_per_pixel - 8));
615 else // 32)
616 fill_chroma<float>(dstp_u, dstp_v, height_uv, rowsize_uv, pitch_uv, 0.0f);
617
618 // alpha
619
2/4
✓ Branch 67 → 68 taken 1 time.
✗ Branch 67 → 84 not taken.
✓ Branch 68 → 69 taken 1 time.
✗ Branch 68 → 82 not taken.
1 if (vi.NumComponents() == 4) {
620
1/2
✓ Branch 70 → 71 taken 1 time.
✗ Branch 70 → 84 not taken.
1 auto dstp_a = src->GetWritePtr(PLANAR_A);
621
1/2
✓ Branch 72 → 73 taken 1 time.
✗ Branch 72 → 84 not taken.
1 auto height_a = src->GetHeight(PLANAR_A);
622
1/2
✓ Branch 74 → 75 taken 1 time.
✗ Branch 74 → 84 not taken.
1 auto rowsize_a = src->GetRowSize(PLANAR_A);
623
1/2
✓ Branch 76 → 77 taken 1 time.
✗ Branch 76 → 84 not taken.
1 auto pitch_a = src->GetPitch(PLANAR_A);
624
1/2
✓ Branch 77 → 78 taken 1 time.
✗ Branch 77 → 79 not taken.
1 if (bits_per_pixel == 8)
625
1/2
✓ Branch 78 → 82 taken 1 time.
✗ Branch 78 → 84 not taken.
1 fill_plane<uint8_t>(dstp_a, height_a, rowsize_a, pitch_a, 255);
626 else if (bits_per_pixel <= 16)
627 fill_plane<uint16_t>(dstp_a, height_a, rowsize_a, pitch_a, (1 << bits_per_pixel) - 1);
628 else // 32)
629 fill_plane<float>(dstp_a, height_a, rowsize_a, pitch_a, 1.0f);
630 }
631 }
632 }
633 1 return src;
634 }
635
636 template<typename pixel_t>
637 static void DrawModeColor2_DrawRect(
638 pixel_t* dstp, int pitch,
639 pixel_t* dstpU, pixel_t* dstpV, int pitchUV,
640 int cx, int cy, // center in luma coords
641 int half_w, int half_h, // half-size in luma coords
642 int swidth, int sheight,
643 pixel_t luma_val,
644 pixel_t u_val, pixel_t v_val,
645 int limit_showwidth // bounds check
646 )
647 {
648 // Draw horizontal top/bottom edges (luma)
649 for (int x = cx - half_w; x <= cx + half_w; x++) {
650 if (x < 0 || x >= limit_showwidth) continue;
651 int y_top = cy - half_h;
652 int y_bot = cy + half_h;
653 if (y_top >= 0 && y_top < limit_showwidth)
654 dstp[x + y_top * pitch] = luma_val;
655 if (y_bot >= 0 && y_bot < limit_showwidth)
656 dstp[x + y_bot * pitch] = luma_val;
657 }
658
659 // Draw vertical left/right edges (luma)
660 for (int y = cy - half_h; y <= cy + half_h; y++) {
661 if (y < 0 || y >= limit_showwidth) continue;
662 int x_l = cx - half_w;
663 int x_r = cx + half_w;
664 if (x_l >= 0 && x_l < limit_showwidth)
665 dstp[x_l + y * pitch] = luma_val;
666 if (x_r >= 0 && x_r < limit_showwidth)
667 dstp[x_r + y * pitch] = luma_val;
668 }
669
670 // Chroma planes (subsampled)
671 const int limit_showwidth_uv = limit_showwidth >> swidth;
672 const int limit_showheight_uv = limit_showwidth >> sheight;
673
674 // Convert luma coordinates to chroma coordinates
675 const int cx_uv = cx >> swidth;
676 const int cy_uv = cy >> sheight;
677 const int half_w_uv = half_w >> swidth;
678 const int half_h_uv = half_h >> sheight;
679
680 // Draw horizontal top/bottom edges (chroma)
681 for (int x = cx_uv - half_w_uv; x <= cx_uv + half_w_uv; x++) {
682 if (x < 0 || x >= limit_showwidth_uv) continue;
683 int y_top = cy_uv - half_h_uv;
684 int y_bot = cy_uv + half_h_uv;
685 if (y_top >= 0 && y_top < limit_showheight_uv) {
686 dstpU[x + y_top * pitchUV] = u_val;
687 dstpV[x + y_top * pitchUV] = v_val;
688 }
689 if (y_bot >= 0 && y_bot < limit_showheight_uv) {
690 dstpU[x + y_bot * pitchUV] = u_val;
691 dstpV[x + y_bot * pitchUV] = v_val;
692 }
693 }
694
695 // Draw vertical left/right edges (chroma)
696 for (int y = cy_uv - half_h_uv; y <= cy_uv + half_h_uv; y++) {
697 if (y < 0 || y >= limit_showheight_uv) continue;
698 int x_l = cx_uv - half_w_uv;
699 int x_r = cx_uv + half_w_uv;
700 if (x_l >= 0 && x_l < limit_showwidth_uv) {
701 dstpU[x_l + y * pitchUV] = u_val;
702 dstpV[x_l + y * pitchUV] = v_val;
703 }
704 if (x_r >= 0 && x_r < limit_showwidth_uv) {
705 dstpU[x_r + y * pitchUV] = u_val;
706 dstpV[x_r + y * pitchUV] = v_val;
707 }
708 }
709 }
710
711
712 // This draws only on luma
713 template<typename pixel_t>
714 static void DrawRadialLine(pixel_t* dstp, int pitch, int limit, int show_bit_shift,
715 double angle_deg, pixel_t val)
716 {
717 double angle_rad = angle_deg * M_PI / 180.0;
718 double R = 124.9 * (1 << show_bit_shift); // same as innerF * scale
719 // Step along the radius
720 int steps = (int)(R * 1.5);
721 for (int s = 0; s < steps; s++) {
722 double t = (double)s / steps;
723 int x = (int)(limit + t * R * cos(angle_rad) + 0.5);
724 int y = (int)(limit - t * R * sin(angle_rad) + 0.5); // V is flipped
725 if (x >= 0 && x <= 2 * limit && y >= 0 && y <= 2 * limit)
726 dstp[x + y * pitch] = val;
727 }
728 }
729
730 // Set to black, alpha to 0.
731 template<typename pixel_t>
732 1 static void ClearArea(
733 uint8_t* dstp, uint8_t* dstp_u, uint8_t* dstp_v, uint8_t* dstp_a,
734 int width, int widthUV,
735 int pitch, int pitchUV, int pitchA,
736 int height, int heightUV, int heightA,
737 int bits_per_pixel, bool full_range)
738 {
739 pixel_t black, middle_chroma, alpha;
740 if constexpr (std::is_integral<pixel_t>::value) {
741
1/4
void ClearArea<unsigned char>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
void ClearArea<unsigned short>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
1 black = full_range ? 0 : (pixel_t)(16 << (bits_per_pixel - 8));
742 1 middle_chroma = (pixel_t)(128 << (bits_per_pixel - 8));
743 1 alpha = 0;
744 }
745 else {
746 black = full_range ? 0.0f : 16.0f / 255.0f;
747 middle_chroma = 0.0f;
748 alpha = 0.0f;
749 }
750
751 // Y
752
2/6
void ClearArea<float>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✗ Branch 16 → 6 not taken.
✗ Branch 16 → 17 not taken.
void ClearArea<unsigned char>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✓ Branch 16 → 6 taken 256 times.
✓ Branch 16 → 17 taken 1 time.
void ClearArea<unsigned short>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✗ Branch 16 → 6 not taken.
✗ Branch 16 → 17 not taken.
257 for (int y = 0; y < height; y++) {
753 512 std::fill_n((pixel_t*)(dstp + y * pitch), width, black);
754 }
755 // UV
756
2/6
void ClearArea<float>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✗ Branch 37 → 18 not taken.
✗ Branch 37 → 38 not taken.
void ClearArea<unsigned char>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✓ Branch 37 → 18 taken 128 times.
✓ Branch 37 → 38 taken 1 time.
void ClearArea<unsigned short>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✗ Branch 37 → 18 not taken.
✗ Branch 37 → 38 not taken.
129 for (int y = 0; y < heightUV; y++) {
757 128 std::fill_n((pixel_t*)(dstp_u + y * pitchUV), widthUV, middle_chroma);
758 256 std::fill_n((pixel_t*)(dstp_v + y * pitchUV), widthUV, middle_chroma);
759 }
760 // Alpha, dimensions same as luma
761 // heightA is zero if no alpha plane
762
1/6
void ClearArea<float>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✗ Branch 49 → 39 not taken.
✗ Branch 49 → 50 not taken.
void ClearArea<unsigned char>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✗ Branch 49 → 39 not taken.
✓ Branch 49 → 50 taken 1 time.
void ClearArea<unsigned short>(unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✗ Branch 49 → 39 not taken.
✗ Branch 49 → 50 not taken.
1 for (int y = 0; y < heightA; y++) {
763 std::fill_n((pixel_t*)(dstp_a + y * pitchA), width, alpha);
764 }
765 1 }
766
767 // Common prelude for Color and Color2 modes.
768 // Allocates dst, optionally clears the below-source area, copies source planes.
769 // Returns the allocated dst frame; populates panel pointer offsets.ű
770 // Full_range flag is filled in constructor, not per frame
771 2 PVideoFrame Histogram::VectorscopePrelude(
772 int n, IScriptEnvironment* env,
773 PVideoFrame& src,
774 // outputs:
775 int& dst_pitch, int& dst_height,
776 int& dst_pitchUV, int& dst_heightUV,
777 int& dst_pitchA, int& dst_heightA,
778 BYTE*& panel, BYTE*& panelU, BYTE*& panelV, BYTE*& panelA)
779 {
780
2/4
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 126 not taken.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 124 not taken.
2 src = child->GetFrame(n, env);
781 2 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
782
783
1/2
✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 127 not taken.
2 BYTE *pdst = dst->GetWritePtr();
784
1/2
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 127 not taken.
2 BYTE *pdstU = dst->GetWritePtr(PLANAR_U);
785
1/2
✓ Branch 12 → 13 taken 2 times.
✗ Branch 12 → 127 not taken.
2 BYTE *pdstV = dst->GetWritePtr(PLANAR_V);
786
1/2
✓ Branch 14 → 15 taken 2 times.
✗ Branch 14 → 127 not taken.
2 BYTE *pdstA = dst->GetWritePtr(PLANAR_A);
787
788
1/2
✓ Branch 16 → 17 taken 2 times.
✗ Branch 16 → 127 not taken.
2 dst_pitch = dst->GetPitch();
789
1/2
✓ Branch 18 → 19 taken 2 times.
✗ Branch 18 → 127 not taken.
2 dst_pitchUV = dst->GetPitch(PLANAR_U);
790
1/2
✓ Branch 20 → 21 taken 2 times.
✗ Branch 20 → 127 not taken.
2 dst_pitchA = dst->GetPitch(PLANAR_A);
791
1/2
✓ Branch 22 → 23 taken 2 times.
✗ Branch 22 → 127 not taken.
2 dst_height = dst->GetHeight();
792
1/2
✓ Branch 24 → 25 taken 2 times.
✗ Branch 24 → 127 not taken.
2 dst_heightUV = dst->GetHeight(PLANAR_U);
793
1/2
✓ Branch 26 → 27 taken 2 times.
✗ Branch 26 → 127 not taken.
2 dst_heightA = dst->GetHeight(PLANAR_A);
794
795 2 const bool has_alpha = dst_heightA > 0;
796
797
1/2
✓ Branch 28 → 29 taken 2 times.
✗ Branch 28 → 127 not taken.
2 const int src_width = src->GetRowSize() / pixelsize;
798
1/2
✓ Branch 30 → 31 taken 2 times.
✗ Branch 30 → 127 not taken.
2 const int src_widthUV = src->GetRowSize(PLANAR_U) / pixelsize;
799
1/2
✓ Branch 32 → 33 taken 2 times.
✗ Branch 32 → 127 not taken.
2 const int src_height = src->GetHeight();
800
1/2
✓ Branch 34 → 35 taken 2 times.
✗ Branch 34 → 127 not taken.
2 const int src_heightUV = src->GetHeight(PLANAR_U);
801
802 2 const int show_size = 1 << show_bits;
803
1/2
✓ Branch 35 → 36 taken 2 times.
✗ Branch 35 → 127 not taken.
2 const int show_size_w_uv = show_size >> vi.GetPlaneWidthSubsampling(PLANAR_U);
804
1/2
✓ Branch 36 → 37 taken 2 times.
✗ Branch 36 → 127 not taken.
2 const int show_size_h_uv = show_size >> vi.GetPlaneHeightSubsampling(PLANAR_U);
805
806
1/2
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 84 taken 2 times.
2 if (keepsource) {
807
808 if (src_height < dst_height) {
809 // in case of Histogram area is higher than source, clear the area below source copy to black + A=0
810 auto pdst_start = pdst + src_height * dst_pitch;
811 auto pdstU_start = pdstU + src_heightUV * dst_pitchUV;
812 auto pdstV_start = pdstV + src_heightUV * dst_pitchUV;
813 auto pdstA_start = pdstA + src_height * dst_pitchA;
814 const int new_height = dst_height - src_height;
815 const int new_height_uv = dst_heightUV - src_heightUV;
816 const int new_height_a = has_alpha ? new_height : 0;
817
818 if (bits_per_pixel == 8)
819 ClearArea<uint8_t>(pdst_start, pdstU_start, pdstV_start, pdstA_start,
820 src_width, src_widthUV,
821 dst_pitch, dst_pitchUV, dst_pitchA,
822 new_height, new_height_uv, new_height_a,
823 bits_per_pixel, full_range);
824 else if (bits_per_pixel <= 16)
825 ClearArea<uint16_t>(pdst_start, pdstU_start, pdstV_start, pdstA_start,
826 src_width, src_widthUV,
827 dst_pitch, dst_pitchUV, dst_pitchA,
828 new_height, new_height_uv, new_height_a,
829 bits_per_pixel, full_range);
830 else
831 ClearArea<float>(pdst_start, pdstU_start, pdstV_start, pdstA_start,
832 src_width, src_widthUV,
833 dst_pitch, dst_pitchUV, dst_pitchA,
834 new_height, new_height_uv, new_height_a,
835 bits_per_pixel, full_range);
836 }
837 // copy source
838 env->BitBlt(pdst, dst_pitch, src->GetReadPtr(), src->GetPitch(), src->GetRowSize(), src->GetHeight());
839 env->BitBlt(pdstU, dst_pitchUV, src->GetReadPtr(PLANAR_U), src->GetPitch(PLANAR_U), src->GetRowSize(PLANAR_U), src->GetHeight(PLANAR_U));
840 env->BitBlt(pdstV, dst_pitchUV, src->GetReadPtr(PLANAR_V), src->GetPitch(PLANAR_V), src->GetRowSize(PLANAR_V), src->GetHeight(PLANAR_V));
841 if (has_alpha)
842 env->BitBlt(pdstA, dst_pitchA, src->GetReadPtr(PLANAR_A), src->GetPitch(PLANAR_A), src->GetRowSize(PLANAR_A), src->GetHeight(PLANAR_A));
843 }
844
845 // panel is with the offset into the histogram panel area (past the source copy)
846
1/4
✗ Branch 84 → 85 not taken.
✓ Branch 84 → 88 taken 2 times.
✗ Branch 86 → 87 not taken.
✗ Branch 86 → 127 not taken.
2 panel = pdst + (keepsource ? src->GetRowSize() : 0);
847
1/4
✗ Branch 89 → 90 not taken.
✓ Branch 89 → 93 taken 2 times.
✗ Branch 91 → 92 not taken.
✗ Branch 91 → 127 not taken.
2 panelU = pdstU + (keepsource ? src->GetRowSize(PLANAR_U) : 0);
848
1/4
✗ Branch 94 → 95 not taken.
✓ Branch 94 → 98 taken 2 times.
✗ Branch 96 → 97 not taken.
✗ Branch 96 → 127 not taken.
2 panelV = pdstV + (keepsource ? src->GetRowSize(PLANAR_V) : 0);
849
4/10
✓ Branch 99 → 100 taken 2 times.
✗ Branch 99 → 109 not taken.
✓ Branch 101 → 102 taken 2 times.
✗ Branch 101 → 127 not taken.
✓ Branch 102 → 103 taken 2 times.
✗ Branch 102 → 109 not taken.
✗ Branch 103 → 104 not taken.
✓ Branch 103 → 107 taken 2 times.
✗ Branch 105 → 106 not taken.
✗ Branch 105 → 127 not taken.
2 panelA = (pdstA && src->GetReadPtr(PLANAR_A)) ? (pdstA + (keepsource ? src->GetRowSize(PLANAR_A) : 0)) : nullptr;
850
851 // Clear below the histogram area (bottom right), if source is higher than histogram area.
852
1/2
✗ Branch 110 → 111 not taken.
✓ Branch 110 → 122 taken 2 times.
2 if (src_height > show_size) {
853 auto pdst_start = panel + show_size * dst_pitch;
854 auto pdstU_start = panelU + show_size_h_uv * dst_pitchUV;
855 auto pdstV_start = panelV + show_size_h_uv * dst_pitchUV;
856 auto pdstA_start = has_alpha ? panelA + show_size * dst_pitchA : nullptr;
857 const int new_height = dst_height - show_size;
858 const int new_height_uv = dst_heightUV - show_size_h_uv;
859 const int new_height_a = has_alpha ? new_height : 0;
860
861 if (bits_per_pixel == 8)
862 ClearArea<uint8_t>(pdst_start, pdstU_start, pdstV_start, pdstA_start,
863 show_size, show_size_w_uv,
864 dst_pitch, dst_pitchUV, dst_pitchA,
865 new_height, new_height_uv, new_height_a,
866 bits_per_pixel, full_range);
867 else if (bits_per_pixel <= 16)
868 ClearArea<uint16_t>(pdst_start, pdstU_start, pdstV_start, pdstA_start,
869 show_size, show_size_w_uv,
870 dst_pitch, dst_pitchUV, dst_pitchA,
871 new_height, new_height_uv, new_height_a,
872 bits_per_pixel, full_range);
873 else
874 ClearArea<float>(pdst_start, pdstU_start, pdstV_start, pdstA_start,
875 show_size, show_size_w_uv,
876 dst_pitch, dst_pitchUV, dst_pitchA,
877 new_height, new_height_uv, new_height_a,
878 bits_per_pixel, full_range);
879 }
880
881 2 return dst;
882 }
883
884 static void GetYUVFromMatrix(
885 int matrix, // AVS_MATRIX_* enum value
886 double R, double G, double B,
887 double& dY, double& dU, double& dV)
888 {
889 double Kr, Kb;
890 if (!GetKrKb(matrix, Kr, Kb)) {
891 // fallback to BT.601
892 Kr = 0.299; Kb = 0.114;
893 }
894 double Kg = 1.0 - Kr - Kb;
895 dY = Kr * R + Kg * G + Kb * B;
896 dU = (B - dY) / (2.0 * (1.0 - Kb));
897 dV = (R - dY) / (2.0 * (1.0 - Kr));
898 }
899
900 template<typename pixel_t>
901 1 static void DrawModeColor2_ClearVectorscopeArea(int bits_per_pixel,
902 uint8_t* dstp8, uint8_t* dstp8_u, uint8_t* dstp8_v, uint8_t* dstp8_a,
903 int pitch, int pitchUV, int pitchA,
904 int height, int heightUV, int heightA,
905 int show_bits, int swidth, int sheight,
906 bool full_range
907 )
908 {
909 1 const int show_size = (1 << show_bits);
910 1 const int show_size_w_uv = show_size >> swidth;
911 1 const int show_size_h_uv = show_size >> sheight;
912 1 const bool has_alpha = heightA > 0;
913
1/6
void DrawModeColor2_ClearVectorscopeArea<float>(int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
void DrawModeColor2_ClearVectorscopeArea<unsigned char>(int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
void DrawModeColor2_ClearVectorscopeArea<unsigned short>(int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
1 const int show_size_a = has_alpha ? show_size : 0;
914
915 // Clear vectorscope area
916
917
1/6
void DrawModeColor2_ClearVectorscopeArea<float>(int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
void DrawModeColor2_ClearVectorscopeArea<unsigned char>(int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 7 not taken.
void DrawModeColor2_ClearVectorscopeArea<unsigned short>(int, unsigned char*, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, int, int, int, int, int, bool):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
1 if (bits_per_pixel == 8)
918 1 ClearArea<uint8_t>(dstp8, dstp8_u, dstp8_v, dstp8_a,
919 show_size, show_size_w_uv, // width
920 pitch, pitchUV, pitchA,
921 show_size, show_size_h_uv, show_size_a, // height
922 bits_per_pixel, full_range);
923 else if (bits_per_pixel <= 16)
924 ClearArea<uint16_t>(dstp8, dstp8_u, dstp8_v, dstp8_a,
925 show_size, show_size_w_uv, // width
926 pitch, pitchUV, pitchA,
927 show_size, show_size_h_uv, show_size_a, // height
928 bits_per_pixel, full_range);
929 else
930 ClearArea<float>(dstp8, dstp8_u, dstp8_v, dstp8_a,
931 show_size, show_size_w_uv, // width
932 pitch, pitchUV, pitchA,
933 show_size, show_size_h_uv, show_size_a, // height
934 bits_per_pixel, full_range);
935 1 }
936
937 template<typename pixel_t>
938 1 static void DrawModeColor2_draw_graticule(int bits_per_pixel, uint8_t* dstp8, int pitch, int height, int show_bits) {
939
940 1 pitch /= sizeof(pixel_t);
941 1 pixel_t* dstp = reinterpret_cast<pixel_t*>(dstp8);
942
943 pixel_t luma128;
944
945 if constexpr (std::is_integral<pixel_t>::value) {
946 1 luma128 = (pixel_t)(128 << (bits_per_pixel - 8));
947 }
948 else {
949 luma128 = c8tof(128);
950 }
951
952 1 const int show_bit_shift = show_bits - 8;
953
954 // 16 240
955 // 16 +---------+
956 // 17 | |
957 // .. | |
958 // 239 | |
959 // 240 +---------+
960
961 // plot valid grey ccir601 square
962 1 const int size = 1 + ((240 - 16) << show_bit_shift); // original 8 bit: 225 0+/-112
963 1 std::fill_n(&dstp[(16 << show_bit_shift) * pitch + (16 << show_bit_shift)], size, luma128);
964 1 std::fill_n(&dstp[(240 << show_bit_shift) * pitch + (16 << show_bit_shift)], size, luma128);
965
966 // vertical lines left and right side
967
2/6
void DrawModeColor2_draw_graticule<float>(int, unsigned char*, int, int, int):
✗ Branch 24 → 23 not taken.
✗ Branch 24 → 25 not taken.
void DrawModeColor2_draw_graticule<unsigned char>(int, unsigned char*, int, int, int):
✓ Branch 22 → 21 taken 223 times.
✓ Branch 22 → 23 taken 1 time.
void DrawModeColor2_draw_graticule<unsigned short>(int, unsigned char*, int, int, int):
✗ Branch 22 → 21 not taken.
✗ Branch 22 → 23 not taken.
224 for (int y = 1 + (16 << show_bit_shift); y < 240 << show_bit_shift; y++) {
968 223 dstp[(16 << show_bit_shift) + y * pitch] = luma128;
969 223 dstp[(240 << show_bit_shift) + y * pitch] = luma128;
970 }
971 1 }
972
973 template<typename pixel_t>
974 static void DrawModeColor2_draw_circle(int bits_per_pixel, uint8_t* dstp8, uint8_t* dstp8_u, uint8_t* dstp8_v,
975 int pitch, int pitchUV, int height, int heightUV, double innerF,
976 int show_bits, int swidth, int sheight, int* deg15c, int* deg15s // precalculated array
977 )
978 {
979
980 pitch /= sizeof(pixel_t);
981 pitchUV /= sizeof(pixel_t);
982 pixel_t* dstp = reinterpret_cast<pixel_t*>(dstp8);
983 pixel_t* dstp_u = reinterpret_cast<pixel_t*>(dstp8_u);
984 pixel_t* dstp_v = reinterpret_cast<pixel_t*>(dstp8_v);
985
986 // possible to display >8 bit data stuffed into 8 bit size
987 const int show_bit_shift = show_bits - 8;
988
989 // plot circles
990
991 // here we do not bother with matrix-correct color representation.
992
993 // six hues in the color-wheel:
994 // LC[3j,3j+1,3j+2], RC[3j,3j+1,3j+2] in YRange[j]+1 and YRange[j+1]
995 int YRange[8] = { -1, 26, 104, 127, 191, 197, 248, 256 };
996 // 2x green, 2x yellow, 3x red
997 int LC[21] = {
998 145, 54, 34,
999 145, 54, 34,
1000 210, 16, 146,
1001 210, 16, 146,
1002 81, 90, 240,
1003 81, 90, 240,
1004 81, 90, 240
1005 };
1006 // cyan, 4x blue, magenta, red:
1007 int RC[21] = {
1008 170, 166, 16,
1009 41, 240, 110,
1010 41, 240, 110,
1011 41, 240, 110,
1012 41, 240, 110,
1013 106, 202, 222,
1014 81, 90, 240
1015 };
1016 float LC_f[21] = {
1017 c8tof(145), uv8tof(54), uv8tof(34),
1018 c8tof(145), uv8tof(54), uv8tof(34),
1019 c8tof(210), uv8tof(16), uv8tof(146),
1020 c8tof(210), uv8tof(16), uv8tof(146),
1021 c8tof(81), uv8tof(90), uv8tof(240),
1022 c8tof(81), uv8tof(90), uv8tof(240),
1023 c8tof(81), uv8tof(90), uv8tof(240)
1024 };
1025 // cyan, 4x blue, magenta, red:
1026 float RC_f[21] = {
1027 c8tof(170), uv8tof(166), uv8tof(16),
1028 c8tof(41), uv8tof(240), uv8tof(110),
1029 c8tof(41), uv8tof(240), uv8tof(110),
1030 c8tof(41), uv8tof(240), uv8tof(110),
1031 c8tof(41), uv8tof(240), uv8tof(110),
1032 c8tof(106), uv8tof(202), uv8tof(222),
1033 c8tof(81), uv8tof(90), uv8tof(240)
1034 };
1035
1036 // example boundary of cyan and blue:
1037 // red = min(r,g,b), blue if g < 2/3 b, green if b < 2/3 g.
1038 // cyan between green and blue.
1039 // thus boundary of cyan and blue at (r,g,b) = (0,170,255), since 2/3*255 = 170.
1040 // => yuv = (127,190,47); hue = -52 degr; sat = 103
1041 // => u'v' = (207,27) (same hue, sat=128)
1042 // similar for the other hues.
1043 // luma
1044
1045 // innerF is used for 15 degree markers as well
1046 double thicknessF = 1.5;
1047 double oneOverThicknessF = 1.0 / thicknessF;
1048 double outerF = innerF + thicknessF * 2.0;
1049 double centerF = innerF + thicknessF;
1050 int64_t innerSq = (int64_t)(innerF * innerF * (1 << (show_bit_shift * 2)));
1051 int64_t outerSq = (int64_t)(outerF * outerF * (1 << (show_bit_shift * 2)));
1052 int activeY = 0;
1053 int xRounder = (1 << swidth) / 2;
1054 int yRounder = (1 << sheight) / 2;
1055
1056 const int limit = (1 << (show_bits - 1)) - 1;
1057 const int limit_showwidth = (1 << show_bits) - 1;
1058 for (int y = -limit; y < limit + 1; y++) {
1059 if (y + limit > YRange[activeY + 1] << show_bit_shift)
1060 activeY++;
1061 for (int x = -limit; x <= 0; x++) {
1062 int64_t distSq = x * x + y * y;
1063 if (distSq <= outerSq && distSq >= innerSq) {
1064
1065 if constexpr (std::is_integral<pixel_t>::value) {
1066 const int factorshift = (bits_per_pixel - 8);
1067 const int MAXINTERP = 256;
1068 double dist = fabs(sqrt((double)distSq * (1.0 / (1 << (2 * show_bit_shift)))) - centerF);
1069 int interp = (int)(256.0f - (255.9f * (oneOverThicknessF * dist)));
1070 // 255.9 is to account for float inprecision, which could cause underflow.
1071
1072 int xP = limit + x;
1073 int yP = limit + y;
1074
1075 dstp[xP + yP * pitch] =
1076 (pixel_t)((interp * (LC[3 * activeY] << factorshift)) >> 8); // left upper half
1077
1078 dstp[limit_showwidth - xP + yP * pitch] =
1079 (pixel_t)((interp * (RC[3 * activeY] << factorshift)) >> 8); // right upper half
1080
1081 xP = (xP + xRounder) >> swidth;
1082 yP = (yP + yRounder) >> sheight;
1083
1084 interp = min(MAXINTERP, interp);
1085 int invInt = (MAXINTERP - interp);
1086
1087 int p_uv;
1088 p_uv = xP + yP * pitchUV;
1089 dstp_u[p_uv] = (pixel_t)((dstp_u[p_uv] * invInt + interp * (LC[3 * activeY + 1] << factorshift)) >> 8); // left half
1090 dstp_v[p_uv] = (pixel_t)((dstp_v[p_uv] * invInt + interp * (LC[3 * activeY + 2] << factorshift)) >> 8); // left half
1091
1092 xP = ((limit_showwidth) >> swidth) - xP;
1093 p_uv = xP + yP * pitchUV;
1094
1095 dstp_u[p_uv] = (pixel_t)((dstp_u[p_uv] * invInt + interp * (RC[3 * activeY + 1] << factorshift)) >> 8); // right half
1096 dstp_v[p_uv] = (pixel_t)((dstp_v[p_uv] * invInt + interp * (RC[3 * activeY + 2] << factorshift)) >> 8); // right half
1097 }
1098 else {
1099 // 32 bit float
1100 const float MAXINTERP = 1.0f;
1101 double dist = fabs(sqrt((double)distSq * (1.0 / (1 << (2 * show_bit_shift)))) - centerF);
1102 float interp = (float)(1.0 - 0.9999 * (oneOverThicknessF * dist));
1103 // 255.9 is to account for float inprecision, which could cause underflow.
1104
1105 int xP = limit + x;
1106 int yP = limit + y;
1107
1108 dstp[xP + yP * pitch] =
1109 (pixel_t)(interp * LC_f[3 * activeY]); // left upper half
1110
1111 dstp[limit_showwidth - xP + yP * pitch] =
1112 (pixel_t)(interp * RC_f[3 * activeY]); // right upper half
1113
1114 xP = (xP + xRounder) >> swidth;
1115 yP = (yP + yRounder) >> sheight;
1116
1117 interp = min(MAXINTERP, interp);
1118 float invInt = (MAXINTERP - interp);
1119
1120 int p_uv;
1121 p_uv = xP + yP * pitchUV;
1122 dstp_u[p_uv] = (pixel_t)(dstp_u[p_uv] * invInt + interp * LC_f[3 * activeY + 1]); // left half
1123 dstp_v[p_uv] = (pixel_t)(dstp_v[p_uv] * invInt + interp * LC_f[3 * activeY + 2]); // left half
1124
1125 xP = ((limit_showwidth) >> swidth) - xP;
1126
1127 p_uv = xP + yP * pitchUV;
1128 dstp_u[p_uv] = (pixel_t)(dstp_u[p_uv] * invInt + interp * RC_f[3 * activeY + 1]); // right half
1129 dstp_v[p_uv] = (pixel_t)(dstp_v[p_uv] * invInt + interp * RC_f[3 * activeY + 2]); // right half
1130 }
1131 }
1132 }
1133 }
1134
1135 // and the 15 degree markers (same as innerF)
1136 // plot white 15 degree marks
1137 for (int i = 0; i < 24; i++) {
1138 if constexpr (sizeof(pixel_t) == 1)
1139 dstp[deg15c[i] + deg15s[i] * pitch] = 235; // 235: Y-maxluma
1140 else if constexpr (sizeof(pixel_t) == 2)
1141 dstp[deg15c[i] + deg15s[i] * pitch] = 235 << (bits_per_pixel - 8); // 235: Y-maxluma
1142 else // if constexpr (sizeof(pixel_t) == 4)
1143 dstp[deg15c[i] + deg15s[i] * pitch] = c8tof(235); // 235: Y-maxluma
1144 }
1145
1146 }
1147
1148
1149 template<typename pixel_t>
1150 1 static void do_vectorscope_color2(
1151 pixel_t* pdstb, pixel_t* pdstbU, pixel_t* pdstbV,
1152 const pixel_t* pY, const pixel_t* pU, const pixel_t* pV,
1153 int dst_pitch, int dst_pitchUV,
1154 int src_pitch, int src_pitchUV,
1155 int src_widthUV, int src_heightUV,
1156 int swidth, int sheight,
1157 int show_bits,
1158 int bits_per_pixel,
1159 bits_conv_constants& d_chroma,
1160 bool full_range
1161 )
1162 {
1163 // 32 bit float Vectorscope is simulated after a 16 bit conversion
1164
1/6
void do_vectorscope_color2<float>(float*, float*, float*, float const*, float const*, float const*, int, int, int, int, int, int, int, int, int, int, bits_conv_constants&, bool):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
void do_vectorscope_color2<unsigned char>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int, int, int, bits_conv_constants&, bool):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
void do_vectorscope_color2<unsigned short>(unsigned short*, unsigned short*, unsigned short*, unsigned short const*, unsigned short const*, unsigned short const*, int, int, int, int, int, int, int, int, int, int, bits_conv_constants&, bool):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
1 const int shift = bits_per_pixel == 32 ? (16 - show_bits) /*n/a*/ : (bits_per_pixel - show_bits);
1165 1 const int max_pos = (1 << show_bits) - 1;
1166 1 auto src_pitchY_chromacorr = (src_pitch << sheight);
1167
1168 if constexpr (sizeof(pixel_t) == 4) {
1169 // ===== FLOAT PATH =====
1170 const float mul_factor = d_chroma.mul_factor;
1171 const float dst_offset = d_chroma.dst_offset;
1172
1173 for (int y = 0; y < src_heightUV; y++) {
1174 for (int x = 0; x < src_widthUV; x++) {
1175 const float uval_f = max(-0.5f, min(0.5f, pU[x]));
1176 const float vval_f = max(-0.5f, min(0.5f, pV[x]));
1177
1178 int uval_posindex = (int)(uval_f * mul_factor + dst_offset + 0.5f);
1179 int vval_posindex = (int)(vval_f * mul_factor + dst_offset + 0.5f);
1180 uval_posindex = max(0, min(max_pos, uval_posindex));
1181 vval_posindex = max(0, min(max_pos, vval_posindex));
1182
1183 pdstb[uval_posindex + vval_posindex * dst_pitch] = pY[x << swidth];
1184 pdstbU[(uval_posindex >> swidth) + (vval_posindex >> sheight) * dst_pitchUV] = uval_f;
1185 pdstbV[(uval_posindex >> swidth) + (vval_posindex >> sheight) * dst_pitchUV] = vval_f;
1186 }
1187 pY += src_pitchY_chromacorr;
1188 pU += src_pitchUV;
1189 pV += src_pitchUV;
1190 }
1191 }
1192 else {
1193 // ===== INTEGER PATH =====
1194 1 const int max_value = (1 << bits_per_pixel) - 1;
1195
1196 // Split into 3 optimized paths based on shift and range
1197 // When shift != 0, that is the dispay bit depth is different from source bit depth, we do conversion
1198 // - full range: use conversion constants
1199 // - limited range: either by downshifting or upshifting.
1200 // E.g. displaying 10 bit data on a 8 bit grid, or displaying 8 bit data on a 10 bit grid.
1201 // We need to convert the chroma values to the display bit depth, taking into account the limited/full range and the shift.
1202
1203
1/4
void do_vectorscope_color2<unsigned char>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int, int, int, bits_conv_constants&, bool):
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 16 not taken.
void do_vectorscope_color2<unsigned short>(unsigned short*, unsigned short*, unsigned short*, unsigned short const*, unsigned short const*, unsigned short const*, int, int, int, int, int, int, int, int, int, int, bits_conv_constants&, bool):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 16 not taken.
1 if (shift == 0) {
1204 // ===== FAST PATH: No scaling needed =====
1205
2/4
void do_vectorscope_color2<unsigned char>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int, int, int, bits_conv_constants&, bool):
✓ Branch 15 → 7 taken 2 times.
✓ Branch 15 → 52 taken 1 time.
void do_vectorscope_color2<unsigned short>(unsigned short*, unsigned short*, unsigned short*, unsigned short const*, unsigned short const*, unsigned short const*, int, int, int, int, int, int, int, int, int, int, bits_conv_constants&, bool):
✗ Branch 15 → 7 not taken.
✗ Branch 15 → 52 not taken.
3 for (int y = 0; y < src_heightUV; y++) {
1206
2/4
void do_vectorscope_color2<unsigned char>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int, int, int, bits_conv_constants&, bool):
✓ Branch 13 → 8 taken 4 times.
✓ Branch 13 → 14 taken 2 times.
void do_vectorscope_color2<unsigned short>(unsigned short*, unsigned short*, unsigned short*, unsigned short const*, unsigned short const*, unsigned short const*, int, int, int, int, int, int, int, int, int, int, bits_conv_constants&, bool):
✗ Branch 13 → 8 not taken.
✗ Branch 13 → 14 not taken.
6 for (int x = 0; x < src_widthUV; x++) {
1207 4 const int uval = max(0, min(max_value, (int)pU[x]));
1208 4 const int vval = max(0, min(max_value, (int)pV[x]));
1209
1210 4 pdstb[uval + vval * dst_pitch] = pY[x << swidth];
1211 4 pdstbU[(uval >> swidth) + (vval >> sheight) * dst_pitchUV] = (pixel_t)uval;
1212 4 pdstbV[(uval >> swidth) + (vval >> sheight) * dst_pitchUV] = (pixel_t)vval;
1213 }
1214 2 pY += src_pitchY_chromacorr;
1215 2 pU += src_pitchUV;
1216 2 pV += src_pitchUV;
1217 }
1218 }
1219 else if (full_range) {
1220 // ===== FULL RANGE PATH: Use conversion constants =====
1221 const float mul_factor = d_chroma.mul_factor;
1222 const int src_offset_i = d_chroma.src_offset_i;
1223 const float dst_offset = d_chroma.dst_offset;
1224
1225 for (int y = 0; y < src_heightUV; y++) {
1226 for (int x = 0; x < src_widthUV; x++) {
1227 const int uval = max(0, min(max_value, (int)pU[x]));
1228 const int vval = max(0, min(max_value, (int)pV[x]));
1229
1230 int uval_posindex = (int)((uval - src_offset_i) * mul_factor + dst_offset + 0.5f);
1231 int vval_posindex = (int)((vval - src_offset_i) * mul_factor + dst_offset + 0.5f);
1232 uval_posindex = max(0, min(max_pos, uval_posindex));
1233 vval_posindex = max(0, min(max_pos, vval_posindex));
1234
1235 pdstb[uval_posindex + vval_posindex * dst_pitch] = pY[x << swidth];
1236 pdstbU[(uval_posindex >> swidth) + (vval_posindex >> sheight) * dst_pitchUV] = (pixel_t)uval;
1237 pdstbV[(uval_posindex >> swidth) + (vval_posindex >> sheight) * dst_pitchUV] = (pixel_t)vval;
1238 }
1239 pY += src_pitchY_chromacorr;
1240 pU += src_pitchUV;
1241 pV += src_pitchUV;
1242 }
1243 }
1244 else {
1245 // ===== LIMITED RANGE PATH: Simple bit shift =====
1246 if (shift > 0) {
1247 // Downshift (e.g., 10-bit -> 8-bit display)
1248 const int rounder = 1 << (shift - 1);
1249 for (int y = 0; y < src_heightUV; y++) {
1250 for (int x = 0; x < src_widthUV; x++) {
1251 const int uval = max(0, min(max_value, (int)pU[x]));
1252 const int vval = max(0, min(max_value, (int)pV[x]));
1253
1254 const int uval_posindex = (uval + rounder) >> shift;
1255 const int vval_posindex = (vval + rounder) >> shift;
1256
1257 pdstb[uval_posindex + vval_posindex * dst_pitch] = pY[x << swidth];
1258 pdstbU[(uval_posindex >> swidth) + (vval_posindex >> sheight) * dst_pitchUV] = (pixel_t)uval;
1259 pdstbV[(uval_posindex >> swidth) + (vval_posindex >> sheight) * dst_pitchUV] = (pixel_t)vval;
1260 }
1261 pY += src_pitchY_chromacorr;
1262 pU += src_pitchUV;
1263 pV += src_pitchUV;
1264 }
1265 }
1266 else {
1267 // Upshift (e.g., 8-bit -> 10-bit display)
1268 const int neg_shift = -shift;
1269 for (int y = 0; y < src_heightUV; y++) {
1270 for (int x = 0; x < src_widthUV; x++) {
1271 const int uval = max(0, min(max_value, (int)pU[x]));
1272 const int vval = max(0, min(max_value, (int)pV[x]));
1273
1274 const int uval_posindex = uval << neg_shift;
1275 const int vval_posindex = vval << neg_shift;
1276
1277 pdstb[uval_posindex + vval_posindex * dst_pitch] = pY[x << swidth];
1278 pdstbU[(uval_posindex >> swidth) + (vval_posindex >> sheight) * dst_pitchUV] = (pixel_t)uval;
1279 pdstbV[(uval_posindex >> swidth) + (vval_posindex >> sheight) * dst_pitchUV] = (pixel_t)vval;
1280 }
1281 pY += src_pitchY_chromacorr;
1282 pU += src_pitchUV;
1283 pV += src_pitchUV;
1284 }
1285 }
1286 }
1287 }
1288 1 }
1289
1290 template<typename pixel_t>
1291 2 static void Draw_VectorScope_circle_targets_axes(int bits_per_pixel,
1292 uint8_t* dstp8, uint8_t* dstp8_u, uint8_t* dstp8_v, int pitch, int pitchUV, int height, int heightUV,
1293 double innerF,
1294 int show_bits, int swidth, int sheight,
1295 histogram_color2_params& params,
1296 ConversionMatrix& conv_matrix,
1297 int matrix, // AVS_MATRIX_* enum value
1298 bits_conv_constants& conv_consts,
1299 bool full_range, int* deg15c, int* deg15s)
1300 {
1301
1302
1/6
void Draw_VectorScope_circle_targets_axes<float>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
void Draw_VectorScope_circle_targets_axes<unsigned char>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
void Draw_VectorScope_circle_targets_axes<unsigned short>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
2 if (params.circle) {
1303 // also the 15 deg marks points
1304 DrawModeColor2_draw_circle<pixel_t>(bits_per_pixel,
1305 dstp8, dstp8_u, dstp8_v,
1306 pitch, pitchUV,
1307 height, heightUV,
1308 innerF,
1309 show_bits, swidth, sheight,
1310 deg15c, deg15s
1311 );
1312 }
1313
1314 // Used for the colorUV square positions, calculated from linear RGB
1315 2 bits_conv_constants conv_consts_fullrange_float_origin;
1316
1/6
void Draw_VectorScope_circle_targets_axes<float>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 26 not taken.
void Draw_VectorScope_circle_targets_axes<unsigned char>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 26 not taken.
void Draw_VectorScope_circle_targets_axes<unsigned short>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 26 not taken.
2 get_bits_conv_constants(conv_consts_fullrange_float_origin, /*use_chroma=*/true,
1317 /*fulls=*/true, full_range,
1318 /*srcBitDepth=*/32, /*dstBitDepth=*/show_bits);
1319
1320 2 const int limit_showwidth = (1 << show_bits) - 1;
1321
1322 2 pitch /= sizeof(pixel_t);
1323 2 pitchUV /= sizeof(pixel_t);
1324 2 pixel_t* dstp = reinterpret_cast<pixel_t*>(dstp8);
1325 2 pixel_t* dstp_u = reinterpret_cast<pixel_t*>(dstp8_u);
1326 2 pixel_t* dstp_v = reinterpret_cast<pixel_t*>(dstp8_v);
1327
1328 // ===== -I AND +Q SIGNAL RGB VALUES FOR VECTORSCOPE GRATICULE =====
1329 // These feed through the same matrix-aware make_yuv path as the color bar patches,
1330 // giving correct UV pixel coordinates for any matrix and any bit depth.
1331 //
1332 // Note: -I and +Q are analog NTSC test signals that don't map cleanly to digital RGB/YUV.
1333 // We maintain two separate specifications for backward compatibility:
1334 //
1335 // RGB-NATIVE: Lifted to studio black (code 16), broadcast-safe
1336 // Used when vectorscope processes RGB sources or when drawing RGB graticules
1337 // -I: RGB(16, 90, 130) at 8-bit → produces Y≈77 after matrix conversion
1338 // +Q: RGB(92, 16, 143) at 8-bit → produces Y≈63 after matrix conversion
1339 //
1340 // YUV-TARGETED: Zero-luma pure chroma definition
1341 // Used when vectorscope processes YUV sources
1342 // -I: Converts to Y=16, Cb=158, Cr=95 (legacy ColorBars YUV output)
1343 // +Q: Converts to Y=16, Cb=174, Cr=149 (legacy ColorBars YUV output)
1344 // Contains out-of-range RGB components (super-blacks)
1345 //
1346 // Note 2: These will not lay exactly on UV's 33° and 123° degree lines, since those
1347 // angles are defined in the original NTSC YIQ color space, which differs from the YUV
1348 // space produced by BT.601/BT.709 matrix conversions.
1349
1350 // this one is not used, this is YUV vectorscope, we cannot determine that the YUV was converted from
1351 // an RGB ColorBars.
1352 /*
1353 static const RGBEntry iq_rgb_native[] = {
1354 { "-I", MINUS_I_R, MINUS_I_G, MINUS_I_B }, // RGB-native (studio black lift)
1355 { "+Q", PLUS_Q_R, PLUS_Q_G, PLUS_Q_B }, // RGB-native (studio black lift)
1356 { "+I", PLUS_I_R, PLUS_I_G, PLUS_I_B }, // n/a ColorBarsHD only, which is YUV-only
1357 };
1358 */
1359
1360 // ColorBars ground truth linear RGB (0.75 amplitude, Rec. BT.801-1)
1361 // Top 2/3 bars: LtGrey, Yellow, Cyan, Green, Magenta, Red, Blue
1362 // (White/LtGrey sits at UV center, not a useful vectorscope target)
1363 struct RGBEntry { const char* name; double r, g, b; };
1364 static const RGBEntry bar_rgb[] = {
1365 { "Yellow", 0.75, 0.75, 0.0 },
1366 { "Cyan", 0.0, 0.75, 0.75 },
1367 { "Green", 0.0, 0.75, 0.0 },
1368 { "Magenta", 0.75, 0.0, 0.75 },
1369 { "Red", 0.75, 0.0, 0.0 },
1370 { "Blue", 0.0, 0.0, 0.75 },
1371 };
1372 static const RGBEntry bar100_rgb[] = {
1373 { "Yellow", 1.0, 1.0, 0.0 },
1374 { "Cyan", 0.0, 1.0, 1.0 },
1375 { "Green", 0.0, 1.0, 0.0 },
1376 { "Magenta", 1.0, 0.0, 1.0 },
1377 { "Red", 1.0, 0.0, 0.0 },
1378 { "Blue", 0.0, 0.0, 1.0 },
1379 };
1380
1381 static const RGBEntry iq_rgb_yuv_targeted[] = {
1382 { "-I", MINUS_I_R_YUV, MINUS_I_G_YUV, MINUS_I_B_YUV }, // YUV-targeted (zero-luma)
1383 { "+Q", PLUS_Q_R_YUV, PLUS_Q_G_YUV, PLUS_Q_B_YUV }, // YUV-targeted (zero-luma)
1384 { "+I", PLUS_I_R_YUV, PLUS_I_G_YUV, PLUS_I_B_YUV }, // ColorBarsHD only (same for both)
1385 };
1386
1387 2 const int half_box = 4 * (1 << (show_bits - 8));
1388
1389 // ---- Pixel position helper ----
1390 // Converts normalised chroma [-0.5..0.5] to vectorscope pixel coordinate.
1391 // Always from full range float, since the YUV squares are obtained from the linear RGB values.
1392 // Target is limited/full range aware.
1393 2 auto uv_to_px_float = [&](double uv_norm) -> int {
1394 return clamp(
1395 (int)((float)uv_norm * conv_consts_fullrange_float_origin.mul_factor + conv_consts_fullrange_float_origin.dst_offset + 0.5f),
1396 0, (1 << show_bits) - 1);
1397 };
1398
1399 // Box color (brownish, visible on the wheel background) ----
1400 pixel_t box_luma, box_u, box_v;
1401 if constexpr (std::is_integral<pixel_t>::value) {
1402 // Tan/beige: Y=80, slightly orange/brown tint
1403 2 box_luma = (pixel_t)(80 << (bits_per_pixel - 8));
1404 2 box_u = (pixel_t)(140 << (bits_per_pixel - 8));
1405 2 box_v = (pixel_t)(120 << (bits_per_pixel - 8));
1406 }
1407 else {
1408 box_luma = c8tof(80);
1409 box_u = uv8tof(140);
1410 box_v = uv8tof(120);
1411 }
1412
1413
1/6
void Draw_VectorScope_circle_targets_axes<float>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 70 not taken.
void Draw_VectorScope_circle_targets_axes<unsigned char>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 56 → 57 not taken.
✓ Branch 56 → 64 taken 2 times.
void Draw_VectorScope_circle_targets_axes<unsigned short>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 56 → 57 not taken.
✗ Branch 56 → 64 not taken.
2 if (params.targets) {
1414
1415 // ---- Draw colorbar target boxes ----
1416 for (auto& e : bar_rgb) {
1417 double dY, dU, dV;
1418 GetYUVFromMatrix(matrix, e.r, e.g, e.b, dY, dU, dV);
1419 int cx;
1420 int cy;
1421 if constexpr (std::is_integral<pixel_t>::value) {
1422 cx = uv_to_px_float(dU);
1423 cy = uv_to_px_float(dV);
1424 }
1425 else {
1426 cx = uv_to_px_float(dU);
1427 cy = uv_to_px_float(dV);
1428 }
1429
1430 DrawModeColor2_DrawRect<pixel_t>(
1431 dstp, pitch, dstp_u, dstp_v, pitchUV,
1432 cx, cy, half_box, half_box,
1433 swidth, sheight,
1434 box_luma, box_u, box_v,
1435 limit_showwidth);
1436
1437 }
1438 }
1439
1440
1/6
void Draw_VectorScope_circle_targets_axes<float>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 78 not taken.
void Draw_VectorScope_circle_targets_axes<unsigned char>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 64 → 65 not taken.
✓ Branch 64 → 72 taken 2 times.
void Draw_VectorScope_circle_targets_axes<unsigned short>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 64 → 65 not taken.
✗ Branch 64 → 72 not taken.
2 if (params.targets100) {
1441
1442 // ---- Draw colorbar target boxes ----
1443 for (auto& e : bar100_rgb) {
1444 double dY, dU, dV;
1445 GetYUVFromMatrix(matrix, e.r, e.g, e.b, dY, dU, dV);
1446 int cx;
1447 int cy;
1448 if constexpr (std::is_integral<pixel_t>::value) {
1449 cx = uv_to_px_float(dU);
1450 cy = uv_to_px_float(dV);
1451 }
1452 else {
1453 cx = uv_to_px_float(dU);
1454 cy = uv_to_px_float(dV);
1455 }
1456
1457 DrawModeColor2_DrawRect<pixel_t>(
1458 dstp, pitch, dstp_u, dstp_v, pitchUV,
1459 cx, cy, half_box, half_box,
1460 swidth, sheight,
1461 box_luma, box_u, box_v,
1462 limit_showwidth);
1463
1464 }
1465 }
1466
1467
1/6
void Draw_VectorScope_circle_targets_axes<float>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 86 not taken.
void Draw_VectorScope_circle_targets_axes<unsigned char>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 72 → 73 not taken.
✓ Branch 72 → 80 taken 2 times.
void Draw_VectorScope_circle_targets_axes<unsigned short>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 72 → 73 not taken.
✗ Branch 72 → 80 not taken.
2 if (params.iq) {
1468 // ---- Draw +Q and -I target boxes ----
1469 // These are matrix-independent (they are phase references, not primaries),
1470 // but still need the same pixel-coordinate conversion.
1471 for (auto& e : iq_rgb_yuv_targeted) {
1472 double dY, dU, dV;
1473 GetYUVFromMatrix(matrix, e.r, e.g, e.b, dY, dU, dV);
1474 int cx = uv_to_px_float(dU);
1475 int cy = uv_to_px_float(dV);
1476 // yuv.u and yuv.v are already the correct pixel_t values at the virtual target
1477 // (show) bit depth.
1478
1479 DrawModeColor2_DrawRect<pixel_t>(
1480 dstp, pitch, dstp_u, dstp_v, pitchUV,
1481 cx, cy, half_box, half_box,
1482 swidth, sheight,
1483 box_luma, box_u, box_v,
1484 limit_showwidth);
1485
1486 }
1487 }
1488
1489 // ---- Radial lines ----
1490 pixel_t line_luma;
1491 if constexpr (std::is_integral<pixel_t>::value)
1492 2 line_luma = (pixel_t)(120 << (bits_per_pixel - 8));
1493 else
1494 line_luma = c8tof(120);
1495
1496 // Angles to draw(matching PPro vectorscope) :
1497 // 0°, 90°, 180°, 270° — the axis cross
1498 // 33°, 123°, 213°, 303° — the ±I/±Q diagonals
1499 // knowing that in UV space these are not exactly at 33° and 123°
1500
1501
1/6
void Draw_VectorScope_circle_targets_axes<float>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 88 → 89 not taken.
✗ Branch 88 → 94 not taken.
void Draw_VectorScope_circle_targets_axes<unsigned char>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 80 → 81 not taken.
✓ Branch 80 → 86 taken 2 times.
void Draw_VectorScope_circle_targets_axes<unsigned short>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 86 not taken.
2 if (params.axes) {
1502 const double angles90[] = {
1503 0.0, 90.0, 180.0, 270.0
1504 };
1505 const int limit = (1 << (show_bits - 1)) - 1;
1506 const int show_bit_shift = show_bits - 8;
1507 for (double ang : angles90)
1508 DrawRadialLine<pixel_t>(dstp, pitch,
1509 limit, show_bit_shift, ang, line_luma);
1510 }
1511
1512
1/6
void Draw_VectorScope_circle_targets_axes<float>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 94 → 95 not taken.
✗ Branch 94 → 100 not taken.
void Draw_VectorScope_circle_targets_axes<unsigned char>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 86 → 87 not taken.
✓ Branch 86 → 92 taken 2 times.
void Draw_VectorScope_circle_targets_axes<unsigned short>(int, unsigned char*, unsigned char*, unsigned char*, int, int, int, int, double, int, int, int, histogram_color2_params&, ConversionMatrix&, int, bits_conv_constants&, bool, int*, int*):
✗ Branch 86 → 87 not taken.
✗ Branch 86 → 92 not taken.
2 if (params.iq_lines) {
1513 const double anglesIQ[] = {
1514 33.0, 123.0, 213.0, 303.0
1515 };
1516 const int limit = (1 << (show_bits - 1)) - 1;
1517 const int show_bit_shift = show_bits - 8;
1518 for (double ang : anglesIQ)
1519 DrawRadialLine<pixel_t>(dstp, pitch,
1520 limit, show_bit_shift, ang, line_luma);
1521 }
1522 2 }
1523
1524
1525 1 PVideoFrame Histogram::DrawModeColor2(int n, IScriptEnvironment* env) {
1526
1527 // all these will get filled by VectorscopePrelude, common for color and color2 modes
1528
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 105 not taken.
1 PVideoFrame src;
1529 BYTE* panel, * panelU, * panelV, * panelA;
1530 int dst_pitch, dst_pitchUV, dst_pitchA, dst_height, dst_heightUV, dst_heightA;
1531
1532 PVideoFrame dst = VectorscopePrelude(n, env,
1533 // outputs
1534 src,
1535 dst_pitch, dst_height,
1536 dst_pitchUV, dst_heightUV,
1537 dst_pitchA, dst_heightA,
1538
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 103 not taken.
1 panel, panelU, panelV, panelA);
1539
1540 1 bits_conv_constants d_chroma;
1541 1 get_bits_conv_constants(d_chroma, /*use_chroma=*/true,
1542
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 26 not taken.
1 full_range, full_range,
1543 bits_per_pixel, /*dstBitDepth=*/show_bits);
1544 // d_chroma.mul_factor and d_chroma.dst_offset are now correct for
1545 // limited-limited or full-full depending on _ColorRange frame property.
1546
1547
1/2
✓ Branch 56 → 57 taken 1 time.
✗ Branch 56 → 101 not taken.
1 int swidth = vi.GetPlaneWidthSubsampling(PLANAR_U);
1548
1/2
✓ Branch 57 → 58 taken 1 time.
✗ Branch 57 → 101 not taken.
1 int sheight = vi.GetPlaneHeightSubsampling(PLANAR_U);
1549
1550 // Clear Vectorscope area (black background, init Alpha to 0 if present)
1551
1/2
✓ Branch 58 → 59 taken 1 time.
✗ Branch 58 → 60 not taken.
1 if (bits_per_pixel == 8)
1552 1 DrawModeColor2_ClearVectorscopeArea<uint8_t>(bits_per_pixel,
1553 panel, panelU, panelV, panelA,
1554 dst_pitch, dst_pitchUV, dst_pitchA,
1555 dst_height, dst_heightUV, dst_heightA,
1556 show_bits, swidth, sheight,
1557
1/2
✓ Branch 59 → 63 taken 1 time.
✗ Branch 59 → 101 not taken.
1 full_range
1558 );
1559 else if (bits_per_pixel <= 16)
1560 DrawModeColor2_ClearVectorscopeArea<uint16_t>(bits_per_pixel,
1561 panel, panelU, panelV, panelA,
1562 dst_pitch, dst_pitchUV, dst_pitchA,
1563 dst_height, dst_heightUV, dst_heightA,
1564 show_bits, swidth, sheight,
1565 full_range
1566 );
1567 else
1568 DrawModeColor2_ClearVectorscopeArea<float>(bits_per_pixel,
1569 panel, panelU, panelV, panelA,
1570 dst_pitch, dst_pitchUV, dst_pitchA,
1571 dst_height, dst_heightUV, dst_heightA,
1572 show_bits, swidth, sheight,
1573 full_range
1574 );
1575
1576 // graticule
1577 // Valid chroma boundary square
1578 // always/never/only-when-limited
1579 // "color" mode's graticule is used for highlight danger zone.
1580 // "color2" mode's graticule is used for drawing chroma boundary rectangle.
1581 // "on" or "auto"+limited range
1582
1/2
✗ Branch 63 → 64 not taken.
✓ Branch 63 → 66 taken 1 time.
1 const bool need_graticule = color2_params.graticule_type == histogram_color2_params::GRATICULE_ON ||
1583 (color2_params.graticule_type == histogram_color2_params::GRATICULE_AUTO && !full_range);
1584
1585
1/2
✓ Branch 68 → 69 taken 1 time.
✗ Branch 68 → 74 not taken.
1 if (need_graticule) {
1586
1/2
✓ Branch 69 → 70 taken 1 time.
✗ Branch 69 → 71 not taken.
1 if (bits_per_pixel == 8)
1587
1/2
✓ Branch 70 → 74 taken 1 time.
✗ Branch 70 → 101 not taken.
1 DrawModeColor2_draw_graticule<uint8_t>(bits_per_pixel, panel, dst_pitch, dst_height, show_bits);
1588 else if (bits_per_pixel <= 16)
1589 DrawModeColor2_draw_graticule<uint16_t>(bits_per_pixel, panel, dst_pitch, dst_height, show_bits);
1590 else
1591 DrawModeColor2_draw_graticule<float>(bits_per_pixel, panel, dst_pitch, dst_height, show_bits);
1592 }
1593
1594 // others: 75% RGB and IQ targets, 15 degree marks, etc.
1595
1/2
✓ Branch 74 → 75 taken 1 time.
✗ Branch 74 → 76 not taken.
1 if (bits_per_pixel == 8)
1596 1 Draw_VectorScope_circle_targets_axes<uint8_t>(bits_per_pixel,
1597 panel, panelU, panelV,
1598 dst_pitch, dst_pitchUV,
1599 dst_height, dst_heightUV,
1600 color2_innerF,
1601 show_bits, swidth, sheight,
1602 1 color2_params, matrix, theMatrix, d_chroma, full_range,
1603
1/2
✓ Branch 75 → 79 taken 1 time.
✗ Branch 75 → 101 not taken.
1 deg15c, deg15s
1604 );
1605 else if (bits_per_pixel <= 16)
1606 Draw_VectorScope_circle_targets_axes<uint16_t>(bits_per_pixel,
1607 panel, panelU, panelV,
1608 dst_pitch, dst_pitchUV,
1609 dst_height, dst_heightUV,
1610 color2_innerF,
1611 show_bits, swidth, sheight,
1612 color2_params, matrix, theMatrix, d_chroma, full_range,
1613 deg15c, deg15s
1614 );
1615 else
1616 Draw_VectorScope_circle_targets_axes<float>(bits_per_pixel,
1617 panel, panelU, panelV,
1618 dst_pitch, dst_pitchUV,
1619 dst_height, dst_heightUV,
1620 color2_innerF,
1621 show_bits, swidth, sheight,
1622 color2_params, matrix, theMatrix, d_chroma, full_range,
1623 deg15c, deg15s
1624 );
1625
1626 // plot vectorscope
1627
1/2
✓ Branch 80 → 81 taken 1 time.
✗ Branch 80 → 101 not taken.
1 const int src_pitch = src->GetPitch(PLANAR_Y) / pixelsize;
1628
1/2
✓ Branch 82 → 83 taken 1 time.
✗ Branch 82 → 101 not taken.
1 const int src_pitchUV = src->GetPitch(PLANAR_U) / pixelsize;
1629
1/2
✓ Branch 84 → 85 taken 1 time.
✗ Branch 84 → 101 not taken.
1 const int src_widthUV = src->GetRowSize(PLANAR_U) / pixelsize;
1630
1/2
✓ Branch 86 → 87 taken 1 time.
✗ Branch 86 → 101 not taken.
1 const int src_heightUV = src->GetHeight(PLANAR_U);
1631
1632
1/2
✓ Branch 88 → 89 taken 1 time.
✗ Branch 88 → 101 not taken.
1 const BYTE* pY = src->GetReadPtr(PLANAR_Y);
1633
1/2
✓ Branch 90 → 91 taken 1 time.
✗ Branch 90 → 101 not taken.
1 const BYTE* pU = src->GetReadPtr(PLANAR_U);
1634
1/2
✓ Branch 92 → 93 taken 1 time.
✗ Branch 92 → 101 not taken.
1 const BYTE* pV = src->GetReadPtr(PLANAR_V);
1635
1636 1 dst_pitch /= pixelsize;
1637 1 dst_pitchUV /= pixelsize;
1638
1639
1/2
✓ Branch 93 → 94 taken 1 time.
✗ Branch 93 → 95 not taken.
1 if(bits_per_pixel == 8)
1640 1 do_vectorscope_color2<uint8_t>(
1641 panel, panelU, panelV,
1642 pY, pU, pV,
1643 dst_pitch, dst_pitchUV,
1644 src_pitch, src_pitchUV,
1645 src_widthUV, src_heightUV,
1646 swidth, sheight,
1647
1/2
✓ Branch 94 → 98 taken 1 time.
✗ Branch 94 → 101 not taken.
1 show_bits, bits_per_pixel, d_chroma, full_range);
1648 else if (bits_per_pixel <= 16)
1649 do_vectorscope_color2<uint16_t>(
1650 (uint16_t *)panel, (uint16_t*)panelU, (uint16_t*)panelV,
1651 (uint16_t*)pY, (uint16_t*)pU, (uint16_t*)pV,
1652 dst_pitch, dst_pitchUV,
1653 src_pitch, src_pitchUV,
1654 src_widthUV, src_heightUV,
1655 swidth, sheight,
1656 show_bits, bits_per_pixel, d_chroma, full_range);
1657 else
1658 do_vectorscope_color2<float>(
1659 (float*)panel, (float*)panelU, (float*)panelV,
1660 (float*)pY, (float*)pU, (float*)pV,
1661 dst_pitch, dst_pitchUV,
1662 src_pitch, src_pitchUV,
1663 src_widthUV, src_heightUV,
1664 swidth, sheight,
1665 show_bits, bits_per_pixel, d_chroma, full_range);
1666
1667 1 return dst;
1668 1 }
1669
1670 template<typename pixel_t, bool chroma_danger>
1671 1 static void DrawModeColor_PlotHistogram_inner(
1672 uint8_t* panel_y, int dstpitch,
1673 const int* histUV,
1674 int show_size, int show_bits,
1675 int bits_per_pixel,
1676 int maxval)
1677 {
1678 1 const int limit16 = 16 << (show_bits - 8);
1679 1 const int limit240 = 240 << (show_bits - 8);
1680 int limit16_pixel, luma235;
1681 if constexpr (std::is_same_v<pixel_t, float>) {
1682 limit16_pixel = 16;
1683 luma235 = 235;
1684 }
1685 else {
1686 1 limit16_pixel = 16 << (bits_per_pixel - 8);
1687 1 luma235 = 235 << (bits_per_pixel - 8);
1688 }
1689 1 const int scale = std::is_same_v<pixel_t, float> ? 1 : (1 << (bits_per_pixel - 8));
1690
1691
2/12
void DrawModeColor_PlotHistogram_inner<float, false>(unsigned char*, int, int const*, int, int, int, int):
✗ Branch 8 → 3 not taken.
✗ Branch 8 → 9 not taken.
void DrawModeColor_PlotHistogram_inner<float, true>(unsigned char*, int, int const*, int, int, int, int):
✗ Branch 16 → 3 not taken.
✗ Branch 16 → 17 not taken.
void DrawModeColor_PlotHistogram_inner<unsigned char, false>(unsigned char*, int, int const*, int, int, int, int):
✓ Branch 8 → 3 taken 256 times.
✓ Branch 8 → 9 taken 1 time.
void DrawModeColor_PlotHistogram_inner<unsigned char, true>(unsigned char*, int, int const*, int, int, int, int):
✗ Branch 16 → 3 not taken.
✗ Branch 16 → 17 not taken.
void DrawModeColor_PlotHistogram_inner<unsigned short, false>(unsigned char*, int, int const*, int, int, int, int):
✗ Branch 8 → 3 not taken.
✗ Branch 8 → 9 not taken.
void DrawModeColor_PlotHistogram_inner<unsigned short, true>(unsigned char*, int, int const*, int, int, int, int):
✗ Branch 16 → 3 not taken.
✗ Branch 16 → 17 not taken.
257 for (int y = 0; y < show_size; y++) {
1692 // ylimited: compile-time eliminated when chroma_danger==false
1693
0/12
void DrawModeColor_PlotHistogram_inner<float, true>(unsigned char*, int, int const*, int, int, int, int):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
void DrawModeColor_PlotHistogram_inner<unsigned char, true>(unsigned char*, int, int const*, int, int, int, int):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
void DrawModeColor_PlotHistogram_inner<unsigned short, true>(unsigned char*, int, int const*, int, int, int, int):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
256 const bool ylimited = chroma_danger && (y < limit16 || y > limit240);
1694 256 auto row = reinterpret_cast<pixel_t*>(panel_y);
1695 256 const int* histRow = histUV + y * show_size;
1696
2/12
void DrawModeColor_PlotHistogram_inner<float, false>(unsigned char*, int, int const*, int, int, int, int):
✗ Branch 6 → 4 not taken.
✗ Branch 6 → 7 not taken.
void DrawModeColor_PlotHistogram_inner<float, true>(unsigned char*, int, int const*, int, int, int, int):
✗ Branch 14 → 8 not taken.
✗ Branch 14 → 15 not taken.
void DrawModeColor_PlotHistogram_inner<unsigned char, false>(unsigned char*, int, int const*, int, int, int, int):
✓ Branch 6 → 4 taken 65536 times.
✓ Branch 6 → 7 taken 256 times.
void DrawModeColor_PlotHistogram_inner<unsigned char, true>(unsigned char*, int, int const*, int, int, int, int):
✗ Branch 14 → 8 not taken.
✗ Branch 14 → 15 not taken.
void DrawModeColor_PlotHistogram_inner<unsigned short, false>(unsigned char*, int, int const*, int, int, int, int):
✗ Branch 6 → 4 not taken.
✗ Branch 6 → 7 not taken.
void DrawModeColor_PlotHistogram_inner<unsigned short, true>(unsigned char*, int, int const*, int, int, int, int):
✗ Branch 14 → 8 not taken.
✗ Branch 14 → 15 not taken.
65792 for (int x = 0; x < show_size; x++) {
1697 65536 int disp_val = (histRow[x] * scale) / maxval;
1698 // x danger check: compile-time eliminated when chroma_danger==false
1699 if constexpr (chroma_danger) {
1700 if (ylimited || x < limit16 || x > limit240)
1701 disp_val -= limit16_pixel;
1702 }
1703 65536 int out = min(luma235, limit16_pixel + disp_val);
1704 if constexpr (std::is_same_v<pixel_t, float>)
1705 row[x] = (float)out / 255.0f;
1706 else
1707 65536 row[x] = (pixel_t)out;
1708 }
1709 256 panel_y += dstpitch;
1710 }
1711 1 }
1712
1713 template<typename pixel_t>
1714 1 static void DrawModeColor_PlotHistogram_dispatch(
1715 bool show_chroma_danger_zone,
1716 uint8_t* panel_y, int dstpitch,
1717 const int* histUV,
1718 int show_size, int show_bits,
1719 int bits_per_pixel,
1720 int maxval)
1721 {
1722
1/6
void DrawModeColor_PlotHistogram_dispatch<float>(bool, unsigned char*, int, int const*, int, int, int, int):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
void DrawModeColor_PlotHistogram_dispatch<unsigned char>(bool, unsigned char*, int, int const*, int, int, int, int):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
void DrawModeColor_PlotHistogram_dispatch<unsigned short>(bool, unsigned char*, int, int const*, int, int, int, int):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
1 if (show_chroma_danger_zone)
1723 DrawModeColor_PlotHistogram_inner<pixel_t, true>(panel_y, dstpitch, histUV, show_size, show_bits, bits_per_pixel, maxval);
1724 else
1725 1 DrawModeColor_PlotHistogram_inner<pixel_t, false>(panel_y, dstpitch, histUV, show_size, show_bits, bits_per_pixel, maxval);
1726 1 }
1727
1728
1729
1730 1 PVideoFrame Histogram::DrawModeColor(int n, IScriptEnvironment* env) {
1731
1732 // all these will get filled by VectorscopePrelude, common for color and color2 modes
1733
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 255 not taken.
1 PVideoFrame src;
1734 BYTE* panel, * panelU, * panelV, * panelA;
1735 int dst_pitch, dst_pitchUV, dst_pitchA, dst_height, dst_heightUV, dst_heightA;
1736
1737 PVideoFrame dst = VectorscopePrelude(n, env,
1738 // outputs
1739 src,
1740 dst_pitch, dst_height,
1741 dst_pitchUV, dst_heightUV,
1742 dst_pitchA, dst_heightA,
1743
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 253 not taken.
1 panel, panelU, panelV, panelA);
1744
1745 // always planar
1746
1747 1 int show_size = 1 << show_bits; // 256 for 8 bits, max 1024x1024 (10 bit resolution) found
1748
1749 1 bits_conv_constants d_chroma;
1750 1 get_bits_conv_constants(d_chroma, /*use_chroma=*/true,
1751
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 26 not taken.
1 full_range, full_range,
1752 bits_per_pixel, /*dstBitDepth=*/show_bits);
1753 // d_chroma.mul_factor and d_chroma.dst_offset are now correct for
1754 // limited-limited or full-full depending on _ColorRange frame property.
1755
1756 // Allocate histogram array, can be huge for 12 bits (4096x4096 = 16 million ints), so use nothrow and check for failure.
1757
1/2
✓ Branch 56 → 57 taken 1 time.
✗ Branch 56 → 58 not taken.
1 int* histUV = new(std::nothrow) int[show_size * show_size];
1758
1/2
✗ Branch 60 → 61 not taken.
✓ Branch 60 → 62 taken 1 time.
1 if (!histUV)
1759 env->ThrowError("Histogram: malloc failure!");
1760
1761 1 memset(histUV, 0, sizeof(int) * show_size * show_size);
1762
1763 // Create histogram from the original src frame's U and V planes.
1764 // We need to take into account the bit depth and the show_bits, as well as the limited/full range
1765 // for scaling to show_bits correctly.
1766
1/2
✓ Branch 63 → 64 taken 1 time.
✗ Branch 63 → 251 not taken.
1 const BYTE* pU = src->GetReadPtr(PLANAR_U);
1767
1/2
✓ Branch 65 → 66 taken 1 time.
✗ Branch 65 → 251 not taken.
1 const BYTE* pV = src->GetReadPtr(PLANAR_V);
1768
1769
1/2
✓ Branch 66 → 67 taken 1 time.
✗ Branch 66 → 251 not taken.
1 int w = origwidth >> vi.GetPlaneWidthSubsampling(PLANAR_U);
1770
1/2
✓ Branch 68 → 69 taken 1 time.
✗ Branch 68 → 251 not taken.
1 int h = src->GetHeight(PLANAR_U);
1771
1/2
✓ Branch 70 → 71 taken 1 time.
✗ Branch 70 → 251 not taken.
1 int p = src->GetPitch(PLANAR_U) / pixelsize;
1772
1773 1 const int max_pos = (1 << show_bits) - 1;
1774 1 const float mul_factor = d_chroma.mul_factor;
1775 1 const float dst_offset = d_chroma.dst_offset;
1776 1 const int src_offset_i = d_chroma.src_offset_i;
1777
1778
1/2
✓ Branch 71 → 72 taken 1 time.
✗ Branch 71 → 89 not taken.
1 if (pixelsize == 1) {
1779
1/2
✓ Branch 72 → 73 taken 1 time.
✗ Branch 72 → 79 not taken.
1 if (show_bits == bits_per_pixel) {
1780 // quick case: no bit depth conversion needed
1781
2/2
✓ Branch 78 → 74 taken 2 times.
✓ Branch 78 → 121 taken 1 time.
3 for (int y = 0; y < h; y++) {
1782
2/2
✓ Branch 76 → 75 taken 4 times.
✓ Branch 76 → 77 taken 2 times.
6 for (int x = 0; x < w; x++) {
1783 4 int u = pU[y * p + x];
1784 4 int v = pV[y * p + x];
1785 4 histUV[(v << 8) + u]++;
1786 }
1787 }
1788 }
1789 else {
1790 // 8 bit data on 10 bit sized screen
1791 // works for both limited and full range, since the conversion is the same for 8 bit source
1792 // (10 bit limited case: mul_factor = 4, dst_offset = 0 for full, dst_offset = 16 for limited)
1793 for (int y = 0; y < h; y++) {
1794 for (int x = 0; x < w; x++) {
1795 const int uval = reinterpret_cast<const uint8_t*>(pU)[y * p + x];
1796 const int vval = reinterpret_cast<const uint8_t*>(pV)[y * p + x];
1797 int uval_posindex = (int)((uval - src_offset_i) * mul_factor + dst_offset + 0.5f);
1798 int vval_posindex = (int)((vval - src_offset_i) * mul_factor + dst_offset + 0.5f);
1799 uval_posindex = max(0, min(max_pos, uval_posindex));
1800 vval_posindex = max(0, min(max_pos, vval_posindex));
1801 histUV[(vval_posindex << show_bits) + uval_posindex]++;
1802 }
1803 }
1804 }
1805 }
1806 else if (pixelsize == 2) {
1807 if (show_bits == bits_per_pixel) {
1808 // quick case: no bit depth conversion needed
1809 for (int y = 0; y < h; y++) {
1810 for (int x = 0; x < w; x++) {
1811 int u = reinterpret_cast<const uint16_t*>(pU)[y * p + x];
1812 int v = reinterpret_cast<const uint16_t*>(pV)[y * p + x];
1813 histUV[(v << show_bits) + u]++;
1814 }
1815 }
1816 }
1817 else {
1818 // works for both limited and full range, since the conversion is the same for 16 bit source (mul_factor = 4, dst_offset = 0 for full, dst_offset = 16 for limited)
1819 for (int y = 0; y < h; y++) {
1820 for (int x = 0; x < w; x++) {
1821 const int uval = reinterpret_cast<const uint16_t*>(pU)[y * p + x];
1822 const int vval = reinterpret_cast<const uint16_t*>(pV)[y * p + x];
1823 int uval_posindex = (int)((uval - src_offset_i) * mul_factor + dst_offset + 0.5f);
1824 int vval_posindex = (int)((vval - src_offset_i) * mul_factor + dst_offset + 0.5f);
1825 uval_posindex = max(0, min(max_pos, uval_posindex));
1826 vval_posindex = max(0, min(max_pos, vval_posindex));
1827 histUV[(vval_posindex << show_bits) + uval_posindex]++;
1828 }
1829 }
1830 }
1831 }
1832 else { // float
1833 // 32 bit data on show_bits bit sized screen
1834 for (int y = 0; y < h; y++) {
1835 for (int x = 0; x < w; x++) {
1836 const float uval_f = max(-0.5f, min(0.5f, reinterpret_cast<const float*>(pU)[y * p + x]));
1837 const float vval_f = max(-0.5f, min(0.5f, reinterpret_cast<const float*>(pV)[y * p + x]));
1838 int uval_posindex = (int)(uval_f * mul_factor + dst_offset + 0.5f);
1839 int vval_posindex = (int)(vval_f * mul_factor + dst_offset + 0.5f);
1840 uval_posindex = max(0, min(max_pos, uval_posindex));
1841 vval_posindex = max(0, min(max_pos, vval_posindex));
1842 histUV[(vval_posindex << show_bits) + uval_posindex]++;
1843 }
1844 }
1845 }
1846 // End of histogram creation.
1847
1848
1/2
✓ Branch 121 → 122 taken 1 time.
✗ Branch 121 → 124 not taken.
2 const bool show_chroma_danger_zone = color2_params.graticule_type == histogram_color2_params::GRATICULE_ON ||
1849
1/4
✗ Branch 122 → 123 not taken.
✓ Branch 122 → 125 taken 1 time.
✗ Branch 123 → 124 not taken.
✗ Branch 123 → 125 not taken.
1 (color2_params.graticule_type == histogram_color2_params::GRATICULE_AUTO && !full_range);
1850
1851 // Plot Histogram on Y.
1852 1 int maxval = 1;
1853 // Should we adjust the divisor (maxval)??
1854
1/2
✓ Branch 126 → 127 taken 1 time.
✗ Branch 126 → 128 not taken.
1 if (pixelsize == 1)
1855
1/2
✓ Branch 127 → 131 taken 1 time.
✗ Branch 127 → 251 not taken.
1 DrawModeColor_PlotHistogram_dispatch<uint8_t>(show_chroma_danger_zone, panel, dst_pitch, histUV, show_size, show_bits, bits_per_pixel, maxval);
1856 else if (pixelsize == 2)
1857 DrawModeColor_PlotHistogram_dispatch<uint16_t>(show_chroma_danger_zone, panel, dst_pitch, histUV, show_size, show_bits, bits_per_pixel, maxval);
1858 else
1859 DrawModeColor_PlotHistogram_dispatch<float>(show_chroma_danger_zone, panel, dst_pitch, histUV, show_size, show_bits, bits_per_pixel, maxval);
1860
1861 // Draw colors - U gradient (x-driven) and V gradient (y-driven)
1862
1/2
✓ Branch 131 → 132 taken 1 time.
✗ Branch 131 → 251 not taken.
1 const int swidth = vi.GetPlaneWidthSubsampling(PLANAR_U);
1863
1/2
✓ Branch 132 → 133 taken 1 time.
✗ Branch 132 → 251 not taken.
1 const int sheight = vi.GetPlaneHeightSubsampling(PLANAR_U);
1864 1 const int uvWidth = show_size >> swidth;
1865 1 const int uvHeight = show_size >> sheight;
1866 1 const int shiftCount = show_bits - bits_per_pixel; // for int types
1867
1/2
✗ Branch 133 → 134 not taken.
✓ Branch 133 → 135 taken 1 time.
1 const int rounder = shiftCount > 0 ? (1 << (shiftCount - 1)) : 0; // for int types when downshifting
1868 1 const int shiftCount_f = show_bits - 8; // ? Why
1869
1870 // U: value depends only on x -> precompute one row, memcpy for all y
1871 // V: value depends only on y -> compute once per row, fill entire row
1872
1873
1/2
✓ Branch 136 → 137 taken 1 time.
✗ Branch 136 → 154 not taken.
1 if (pixelsize == 1) {
1874 // --- U ---
1875 // Precompute one row
1876
1/2
✓ Branch 139 → 140 taken 1 time.
✗ Branch 139 → 239 not taken.
1 std::vector<uint8_t> uRow(uvWidth);
1877
2/2
✓ Branch 144 → 142 taken 128 times.
✓ Branch 144 → 145 taken 1 time.
129 for (int x = 0; x < uvWidth; x++)
1878 128 uRow[x] = (uint8_t)((x << swidth) >> shiftCount);
1879 1 auto p = panelU;
1880
2/2
✓ Branch 148 → 146 taken 128 times.
✓ Branch 148 → 149 taken 1 time.
129 for (int y = 0; y < uvHeight; y++, p += dst_pitchUV)
1881 128 memcpy(p, uRow.data(), uvWidth);
1882 // --- V ---
1883 1 p = panelV;
1884
2/2
✓ Branch 151 → 150 taken 128 times.
✓ Branch 151 → 152 taken 1 time.
129 for (int y = 0; y < uvHeight; y++, p += dst_pitchUV) {
1885 128 uint8_t vval = (uint8_t)(((y << sheight) + rounder) >> shiftCount);
1886 128 memset(p, vval, uvWidth);
1887 }
1888 1 }
1889 else if (pixelsize == 2) {
1890 // --- U ---
1891 std::vector<uint16_t> uRow(uvWidth);
1892 if (shiftCount >= 0) {
1893 for (int x = 0; x < uvWidth; x++)
1894 uRow[x] = (uint16_t)(((x << swidth) + rounder) >> shiftCount);
1895 }
1896 else {
1897 for (int x = 0; x < uvWidth; x++)
1898 uRow[x] = (uint16_t)((x << swidth) << -shiftCount);
1899 }
1900 auto p = panelU;
1901 for (int y = 0; y < uvHeight; y++, p += dst_pitchUV)
1902 memcpy(p, uRow.data(), uvWidth * sizeof(uint16_t));
1903
1904 // --- V ---
1905 p = panelV;
1906 if (shiftCount >= 0) {
1907 for (int y = 0; y < uvHeight; y++, p += dst_pitchUV) {
1908 uint16_t vval = (uint16_t)(((y << sheight) + rounder) >> shiftCount);
1909 std::fill_n(reinterpret_cast<uint16_t*>(p), uvWidth, vval);
1910 }
1911 }
1912 else {
1913 for (int y = 0; y < uvHeight; y++, p += dst_pitchUV) {
1914 uint16_t vval = (uint16_t)((y << sheight) << -shiftCount);
1915 std::fill_n(reinterpret_cast<uint16_t*>(p), uvWidth, vval);
1916 }
1917 }
1918 }
1919 else { // float
1920 // --- U ---
1921 std::vector<float> uRow(uvWidth);
1922 for (int x = 0; x < uvWidth; x++)
1923 uRow[x] = uv8tof((x << swidth) >> shiftCount_f);
1924 auto p = panelU;
1925 for (int y = 0; y < uvHeight; y++, p += dst_pitchUV)
1926 memcpy(p, uRow.data(), uvWidth * sizeof(float));
1927 // --- V ---
1928 p = panelV;
1929 for (int y = 0; y < uvHeight; y++, p += dst_pitchUV) {
1930 float vval = uv8tof((y << sheight) >> shiftCount_f);
1931 std::fill_n(reinterpret_cast<float*>(p), uvWidth, vval);
1932 }
1933 }
1934
1935
1/2
✓ Branch 229 → 230 taken 1 time.
✗ Branch 229 → 231 not taken.
1 delete[] histUV;
1936
1937 // others: RGB and IQ targets, 15 degree marks, etc
1938
1/2
✓ Branch 231 → 232 taken 1 time.
✗ Branch 231 → 233 not taken.
1 if (bits_per_pixel == 8)
1939 1 Draw_VectorScope_circle_targets_axes<uint8_t>(bits_per_pixel,
1940 panel, panelU, panelV,
1941 dst_pitch, dst_pitchUV,
1942 dst_height, dst_heightUV,
1943 color2_innerF,
1944 show_bits, swidth, sheight,
1945 1 color2_params, matrix, theMatrix, d_chroma, full_range,
1946
1/2
✓ Branch 232 → 236 taken 1 time.
✗ Branch 232 → 251 not taken.
1 deg15c, deg15s
1947 );
1948 else if (bits_per_pixel <= 16)
1949 Draw_VectorScope_circle_targets_axes<uint16_t>(bits_per_pixel,
1950 panel, panelU, panelV,
1951 dst_pitch, dst_pitchUV,
1952 dst_height, dst_heightUV,
1953 color2_innerF,
1954 show_bits, swidth, sheight,
1955 color2_params, matrix, theMatrix, d_chroma, full_range,
1956 deg15c, deg15s
1957 );
1958 else
1959 Draw_VectorScope_circle_targets_axes<float>(bits_per_pixel,
1960 panel, panelU, panelV,
1961 dst_pitch, dst_pitchUV,
1962 dst_height, dst_heightUV,
1963 color2_innerF,
1964 show_bits, swidth, sheight,
1965 color2_params, matrix, theMatrix, d_chroma, full_range,
1966 deg15c, deg15s
1967 );
1968
1969 1 return dst;
1970 1 }
1971
1972
1973 1 PVideoFrame Histogram::DrawModeLevels(int n, IScriptEnvironment* env) {
1974
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 604 not taken.
1 PVideoFrame src = child->GetFrame(n, env);
1975
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 602 not taken.
1 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
1976
1/2
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 600 not taken.
1 BYTE* dstp = dst->GetWritePtr();
1977
1978 // Note: drawing colors are of limited range independently from clip range
1979 // bool full_range is filled in ctor.
1980
1981 1 int show_size = 1 << show_bits;
1982
1983
1/2
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 600 not taken.
1 const bool isGrey = vi.IsY();
1984
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 1 time.
1 const int planecount = isGrey ? 1 : 3;
1985
1/2
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 600 not taken.
1 const bool RGB = vi.IsRGB();
1986 1 const bool isFloat = (bits_per_pixel == 32);
1987
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 1 time.
1 const int color_shift = isFloat ? 0 : (bits_per_pixel - 8);
1988
1/2
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 17 not taken.
1 const int max_pixel_value = bits_per_pixel <= 16 ? (1 << bits_per_pixel) - 1 : 0; // float: n/a
1989
1/2
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 1 time.
1 const float color_shift_factor = isFloat ? 1.0f / 255.0f : max_pixel_value / 255.0f;
1990
1991 int plane_default_black[3] = {
1992
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 1 time.
1 RGB ? 0 : (16 << color_shift),
1993 1 RGB ? 0 : (128 << color_shift),
1994 1 RGB ? 0 : (128 << color_shift)
1995
2/4
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 1 time.
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 1 time.
2 };
1996 1 float plane_default_black_f[3] = {
1997
1/2
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 1 time.
1 RGB ? 0 : 16 / 255.0f,
1998 RGB ? 0 : 0.0f,
1999 RGB ? 0 : 0.0f
2000 1 };
2001
2002 1 const int planesYUV[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A};
2003 1 const int planesRGB[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A};
2004
2/8
✓ Branch 33 → 34 taken 1 time.
✗ Branch 33 → 600 not taken.
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 37 taken 1 time.
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 600 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 38 not taken.
1 const int *planes = vi.IsYUV() || vi.IsYUVA() ? planesYUV : planesRGB;
2005
2006
1/2
✓ Branch 39 → 40 taken 1 time.
✗ Branch 39 → 117 not taken.
1 if (keepsource) {
2007
3/6
✓ Branch 41 → 42 taken 1 time.
✗ Branch 41 → 600 not taken.
✓ Branch 43 → 44 taken 1 time.
✗ Branch 43 → 600 not taken.
✓ Branch 44 → 45 taken 1 time.
✗ Branch 44 → 117 not taken.
1 if (src->GetHeight() < dst->GetHeight()) {
2008 // fill empty area in the right bottom part
2009
3/6
✓ Branch 46 → 47 taken 1 time.
✗ Branch 46 → 600 not taken.
✓ Branch 48 → 49 taken 1 time.
✗ Branch 48 → 600 not taken.
✓ Branch 50 → 51 taken 1 time.
✗ Branch 50 → 600 not taken.
1 const int fillSize = (dst->GetHeight() - src->GetHeight()) * dst->GetPitch();
2010
2/4
✓ Branch 52 → 53 taken 1 time.
✗ Branch 52 → 600 not taken.
✓ Branch 54 → 55 taken 1 time.
✗ Branch 54 → 600 not taken.
1 const int fillStart = src->GetHeight() * dst->GetPitch();
2011
2012
1/4
✓ Branch 55 → 56 taken 1 time.
✗ Branch 55 → 57 not taken.
✗ Branch 55 → 67 not taken.
✗ Branch 55 → 77 not taken.
1 switch (pixelsize) {
2013 1 case 1: memset(dstp + fillStart, plane_default_black[0], fillSize); break;
2014 case 2: std::fill_n((uint16_t *)(dstp + fillStart), fillSize / sizeof(uint16_t), plane_default_black[0]); break;
2015 case 4: std::fill_n((float *)(dstp + fillStart), fillSize / sizeof(float), plane_default_black_f[0]); break;
2016 }
2017
2018 // first plane is already processed
2019 // dont't touch Alpha
2020
2/2
✓ Branch 116 → 78 taken 2 times.
✓ Branch 116 → 117 taken 1 time.
3 for (int p = 1; p < planecount; p++) {
2021 2 const int plane = planes[p];
2022
1/2
✓ Branch 79 → 80 taken 2 times.
✗ Branch 79 → 600 not taken.
2 BYTE* ptr = dst->GetWritePtr(plane);
2023
2024
3/6
✓ Branch 81 → 82 taken 2 times.
✗ Branch 81 → 600 not taken.
✓ Branch 83 → 84 taken 2 times.
✗ Branch 83 → 600 not taken.
✓ Branch 85 → 86 taken 2 times.
✗ Branch 85 → 600 not taken.
2 const int fillSize = (dst->GetHeight(plane) - src->GetHeight(plane)) * dst->GetPitch(plane);
2025
2/4
✓ Branch 87 → 88 taken 2 times.
✗ Branch 87 → 600 not taken.
✓ Branch 89 → 90 taken 2 times.
✗ Branch 89 → 600 not taken.
2 const int fillStart = src->GetHeight(plane) * dst->GetPitch(plane);
2026
1/4
✓ Branch 90 → 91 taken 2 times.
✗ Branch 90 → 95 not taken.
✗ Branch 90 → 105 not taken.
✗ Branch 90 → 115 not taken.
2 switch (pixelsize) {
2027
1/2
✗ Branch 91 → 92 not taken.
✓ Branch 91 → 93 taken 2 times.
2 case 1: memset(ptr + fillStart, RGB ? 0 : plane_default_black[p], fillSize); break;
2028 case 2: std::fill_n((uint16_t*)(ptr + fillStart), fillSize / sizeof(uint16_t), plane_default_black[p]); break;
2029 case 4: std::fill_n((float*)(ptr + fillStart), fillSize / sizeof(float), plane_default_black_f[p]); break;
2030 }
2031 }
2032 }
2033 }
2034
2035 // counters
2036 1 int bufsize = sizeof(uint32_t)*show_size;
2037
1/2
✓ Branch 117 → 118 taken 1 time.
✗ Branch 117 → 600 not taken.
1 uint32_t *histPlane1 = static_cast<uint32_t*>(env->Allocate(bufsize * planecount, 16, AVS_NORMAL_ALLOC));
2038
1/2
✗ Branch 118 → 119 not taken.
✓ Branch 118 → 120 taken 1 time.
1 if (!histPlane1)
2039 env->ThrowError("Histogram: Could not reserve memory.");
2040 uint32_t *histPlanes[3] = {
2041 histPlane1,
2042 1 planecount == 1 ? nullptr : histPlane1 + show_size,
2043 1 planecount == 1 ? nullptr : histPlane1 + 2 * show_size
2044
2/4
✓ Branch 120 → 121 taken 1 time.
✗ Branch 120 → 122 not taken.
✓ Branch 123 → 124 taken 1 time.
✗ Branch 123 → 125 not taken.
2 };
2045 1 std::fill_n(histPlane1, show_size * planecount, 0);
2046
2047
1/2
✓ Branch 135 → 136 taken 1 time.
✗ Branch 135 → 137 not taken.
1 const int xstart = keepsource ? origwidth : 0; // drawing starts at this column
2048
2049 // copy planes
2050 // luma or G
2051
1/2
✓ Branch 138 → 139 taken 1 time.
✗ Branch 138 → 150 not taken.
1 if (keepsource) {
2052
6/12
✓ Branch 140 → 141 taken 1 time.
✗ Branch 140 → 600 not taken.
✓ Branch 142 → 143 taken 1 time.
✗ Branch 142 → 600 not taken.
✓ Branch 144 → 145 taken 1 time.
✗ Branch 144 → 600 not taken.
✓ Branch 146 → 147 taken 1 time.
✗ Branch 146 → 600 not taken.
✓ Branch 148 → 149 taken 1 time.
✗ Branch 148 → 600 not taken.
✓ Branch 149 → 150 taken 1 time.
✗ Branch 149 → 600 not taken.
1 env->BitBlt(dstp, dst->GetPitch(), src->GetReadPtr(), src->GetPitch(), src->GetRowSize(), src->GetHeight());
2053 }
2054
2/4
✓ Branch 150 → 151 taken 1 time.
✗ Branch 150 → 600 not taken.
✓ Branch 151 → 152 taken 1 time.
✗ Branch 151 → 595 not taken.
1 if (vi.IsPlanar()) {
2055 // copy rest planes
2056
1/2
✓ Branch 152 → 153 taken 1 time.
✗ Branch 152 → 170 not taken.
1 if (keepsource) {
2057
3/4
✓ Branch 168 → 169 taken 3 times.
✗ Branch 168 → 600 not taken.
✓ Branch 169 → 154 taken 2 times.
✓ Branch 169 → 170 taken 1 time.
3 for (int p = 1; p < vi.NumComponents(); p++) {
2058 2 const int plane = planes[p];
2059
7/14
✓ Branch 155 → 156 taken 2 times.
✗ Branch 155 → 600 not taken.
✓ Branch 157 → 158 taken 2 times.
✗ Branch 157 → 600 not taken.
✓ Branch 159 → 160 taken 2 times.
✗ Branch 159 → 600 not taken.
✓ Branch 161 → 162 taken 2 times.
✗ Branch 161 → 600 not taken.
✓ Branch 163 → 164 taken 2 times.
✗ Branch 163 → 600 not taken.
✓ Branch 165 → 166 taken 2 times.
✗ Branch 165 → 600 not taken.
✓ Branch 166 → 167 taken 2 times.
✗ Branch 166 → 600 not taken.
2 env->BitBlt(dst->GetWritePtr(plane), dst->GetPitch(plane), src->GetReadPtr(plane), src->GetPitch(plane), src->GetRowSize(plane), src->GetHeight(plane));
2060 }
2061 }
2062
2063 1 const int max_show_pixel_value = show_size - 1;
2064
2065 // ---------------------------------------------------
2066 // accumulate population: fill histogram array from pixels
2067
2/2
✓ Branch 313 → 171 taken 3 times.
✓ Branch 313 → 314 taken 1 time.
4 for (int p = 0; p < planecount; p++) {
2068 3 const int plane = planes[p];
2069
4/4
✓ Branch 171 → 172 taken 2 times.
✓ Branch 171 → 173 taken 1 time.
✓ Branch 172 → 173 taken 1 time.
✓ Branch 172 → 174 taken 1 time.
3 const bool chroma = (plane == PLANAR_U || plane == PLANAR_V);
2070
1/2
✓ Branch 176 → 177 taken 3 times.
✗ Branch 176 → 599 not taken.
3 const BYTE* srcp = src->GetReadPtr(plane);
2071
2072
1/2
✓ Branch 178 → 179 taken 3 times.
✗ Branch 178 → 599 not taken.
3 const int w = src->GetRowSize(plane) / pixelsize;
2073
1/2
✓ Branch 180 → 181 taken 3 times.
✗ Branch 180 → 599 not taken.
3 const int h = src->GetHeight(plane);
2074
1/2
✓ Branch 182 → 183 taken 3 times.
✗ Branch 182 → 599 not taken.
3 const int pitch = src->GetPitch(plane) / pixelsize;
2075
2076 // accumulator of current plane
2077 // size: show_size (256 or 1024)
2078 3 uint32_t *hist = histPlanes[p];
2079
2080 3 bits_conv_constants d;
2081
2/2
✓ Branch 183 → 184 taken 2 times.
✓ Branch 183 → 205 taken 1 time.
3 get_bits_conv_constants(d, chroma, full_range, full_range, bits_per_pixel/*source_bitdepth*/, show_bits /*target_bitdepth*/);
2082
2083
1/2
✓ Branch 235 → 236 taken 3 times.
✗ Branch 235 → 265 not taken.
3 if(pixelsize==1) {
2084 3 const uint8_t *srcp8 = reinterpret_cast<const uint8_t *>(srcp);
2085
1/2
✓ Branch 236 → 237 taken 3 times.
✗ Branch 236 → 243 not taken.
3 if (show_bits == bits_per_pixel) {
2086 // Exact. 8 bit clip into 8 bit histogram
2087
2/2
✓ Branch 242 → 238 taken 6 times.
✓ Branch 242 → 312 taken 3 times.
9 for (int y = 0; y < h; y++) {
2088
2/2
✓ Branch 240 → 239 taken 24 times.
✓ Branch 240 → 241 taken 6 times.
30 for (int x = 0; x < w; x++) {
2089 24 hist[srcp8[x]]++;
2090 }
2091 6 srcp8 += pitch;
2092 }
2093 }
2094 else {
2095 // 8 bit clip into 8,9,... bit histogram
2096 if (full_range) {
2097 // full range: stretch
2098 if (chroma) {
2099 const float dst_offset_plus_round = d.dst_offset + 0.5f;
2100 for (int y = 0; y < h; y++) {
2101 for (int x = 0; x < w; x++) {
2102 hist[clamp((int)((srcp8[x] - d.src_offset_i) * d.mul_factor + dst_offset_plus_round), 0, max_show_pixel_value)]++;
2103 }
2104 srcp8 += pitch;
2105 }
2106 }
2107 else {
2108 // src_offset and dst_offset is 0
2109 for (int y = 0; y < h; y++) {
2110 for (int x = 0; x < w; x++) {
2111 hist[min((int)(srcp8[x] * d.mul_factor + 0.5f), max_show_pixel_value)]++;
2112 }
2113 srcp8 += pitch;
2114 }
2115 }
2116 }
2117 else {
2118 const int invshift = show_bits - bits_per_pixel;
2119 // limited range: shift
2120 for (int y = 0; y < h; y++) {
2121 for (int x = 0; x < w; x++) {
2122 hist[(int)srcp8[x] << invshift]++;
2123 }
2124 srcp8 += pitch;
2125 }
2126 }
2127 }
2128 }
2129 else if (pixelsize == 2) {
2130 const uint16_t* srcp16 = reinterpret_cast<const uint16_t*>(srcp);
2131 if (show_bits == bits_per_pixel) {
2132 // Exact. e.g. 10 bit clip into 10 bit histogram
2133 for (int y = 0; y < h; y++) {
2134 for (int x = 0; x < w; x++) {
2135 hist[min((int)srcp16[x], max_show_pixel_value)]++;
2136 }
2137 srcp16 += pitch;
2138 }
2139 }
2140 else {
2141 // 10 bit clip into 8,9,10,11,12,... bit histogram
2142 if (full_range) {
2143 // full range: stretch
2144 if (chroma) {
2145 const float dst_offset_plus_round = d.dst_offset + 0.5f;
2146 for (int y = 0; y < h; y++) {
2147 for (int x = 0; x < w; x++) {
2148 hist[clamp((int)((srcp16[x] - d.src_offset_i) * d.mul_factor + dst_offset_plus_round), 0, max_show_pixel_value)]++;
2149 }
2150 srcp16 += pitch;
2151 }
2152 }
2153 else {
2154 // src_offset and dst_offset is 0
2155 for (int y = 0; y < h; y++) {
2156 for (int x = 0; x < w; x++) {
2157 hist[min((int)(srcp16[x] * d.mul_factor + 0.5f), max_show_pixel_value)]++;
2158 }
2159 srcp16 += pitch;
2160 }
2161 }
2162 }
2163 else {
2164 // limited range: shift. Up or down
2165 const int shift = bits_per_pixel - show_bits;
2166 if (shift < 0) {
2167 // 10 bit clip into 11 bit histogram
2168 int invshift = -shift;
2169 for (int y = 0; y < h; y++) {
2170 for (int x = 0; x < w; x++) {
2171 hist[min(srcp16[x] << invshift, max_show_pixel_value)]++;
2172 }
2173 srcp16 += pitch;
2174 }
2175 }
2176 else {
2177 // e.g.10 bit clip into 8-9 bit histogram
2178 const int round = 1 << (shift - 1);
2179 for (int y = 0; y < h; y++) {
2180 for (int x = 0; x < w; x++) {
2181 hist[min((srcp16[x] + round) >> shift, max_show_pixel_value)]++;
2182 }
2183 srcp16 += pitch;
2184 }
2185 }
2186 }
2187 }
2188 }
2189 else {
2190 // create fake Histogram 32 bit float
2191 const float *srcp32 = reinterpret_cast<const float *>(srcp);
2192 const float dst_offset_plus_round = d.dst_offset + 0.5f;
2193 for (int y = 0; y < h; y++) {
2194 for (int x = 0; x < w; x++) {
2195 hist[clamp((int)(srcp32[x] * d.mul_factor + dst_offset_plus_round), 0, max_show_pixel_value)]++;
2196 }
2197 srcp32 += pitch;
2198 }
2199 }
2200 }
2201 // accumulate end
2202 // ---------------------------------------------------
2203
2204 1 int pos_shift = (show_bits - 8);
2205 1 int show_middle_pos = (128 << pos_shift);
2206 // draw planes
2207
2/2
✓ Branch 516 → 315 taken 3 times.
✓ Branch 516 → 517 taken 1 time.
4 for (int p = 0; p < planecount; p++) {
2208 3 const int plane = planes[p];
2209
2210
1/2
✓ Branch 315 → 316 taken 3 times.
✗ Branch 315 → 600 not taken.
3 int swidth = vi.GetPlaneWidthSubsampling(plane);
2211
1/2
✓ Branch 316 → 317 taken 3 times.
✗ Branch 316 → 600 not taken.
3 int sheight = vi.GetPlaneHeightSubsampling(plane);
2212
2213 // Draw Unsafe zone (UV-graph)
2214
2215
1/2
✓ Branch 318 → 319 taken 3 times.
✗ Branch 318 → 600 not taken.
3 unsigned char* pdstb = dst->GetWritePtr(plane);
2216 3 pdstb += (xstart*pixelsize) >> swidth; // next to the source image if kept
2217
2218
1/2
✓ Branch 320 → 321 taken 3 times.
✗ Branch 320 → 600 not taken.
3 const int dstPitch = dst->GetPitch(plane);
2219
2220 // Clear Y/U/V or B, R G
2221 3 BYTE *ptr = pdstb;
2222
3/4
✓ Branch 346 → 347 taken 771 times.
✗ Branch 346 → 600 not taken.
✓ Branch 347 → 322 taken 768 times.
✓ Branch 347 → 348 taken 3 times.
771 for (int y = 0; y < dst->GetHeight() >> sheight; y++) {
2223
1/4
✓ Branch 322 → 323 taken 768 times.
✗ Branch 322 → 324 not taken.
✗ Branch 322 → 334 not taken.
✗ Branch 322 → 344 not taken.
768 switch (pixelsize) {
2224 768 case 1: memset(ptr, plane_default_black[p], show_size >> swidth); break;
2225 case 2: std::fill_n((uint16_t *)(ptr), show_size >> swidth, plane_default_black[p]); break;
2226 case 4: std::fill_n((float *)(ptr), show_size >> swidth, plane_default_black_f[p]); break;
2227 }
2228 768 ptr += dstPitch;
2229 }
2230
2231
2/4
✓ Branch 348 → 349 taken 3 times.
✗ Branch 348 → 376 not taken.
✗ Branch 349 → 350 not taken.
✓ Branch 349 → 376 taken 3 times.
3 if (!RGB && markers) {
2232 // Draw Unsafe zone (Y-graph)
2233 const int color_unsafeZones[3] = { 32, 16, 160 };
2234 const float color_unsafeZones_f[3] = { c8tof(32), uv8tof(16), uv8tof(160) };
2235 int color_usz = color_unsafeZones[p];
2236 int color_i = color_usz << color_shift;
2237 float color_f = color_unsafeZones_f[p];
2238 ptr = pdstb + 0 * dstPitch;;
2239
2240 for (int y = 0; y <= 64 >> sheight; y++) {
2241 int x = 0;
2242 for (; x < (16 << pos_shift) >> swidth; x++) {
2243 if (pixelsize == 1)
2244 ptr[x] = color_i;
2245 else if (pixelsize == 2)
2246 reinterpret_cast<uint16_t *>(ptr)[x] = color_i;
2247 else
2248 reinterpret_cast<float *>(ptr)[x] = color_f;
2249 }
2250 for (x = (236 << pos_shift) >> swidth; x < (show_size >> swidth); x++) { // or (235 << pos_shift) + 1?
2251 if (pixelsize == 1)
2252 ptr[x] = color_i;
2253 else if (pixelsize == 2)
2254 reinterpret_cast<uint16_t *>(ptr)[x] = color_i;
2255 else
2256 reinterpret_cast<float *>(ptr)[x] = color_f;
2257 }
2258 ptr += dstPitch;
2259 }
2260 }
2261
2262
1/2
✗ Branch 376 → 377 not taken.
✓ Branch 376 → 515 taken 3 times.
3 if (markers) {
2263 if (RGB) {
2264 // nice gradients
2265 int StartY;
2266 switch (plane) {
2267 case PLANAR_R: StartY = 0 + 0; break;
2268 case PLANAR_G: StartY = 64 + 16; break;
2269 case PLANAR_B: StartY = 64 + 16 + 64 + 16; break;
2270 }
2271 ptr = pdstb + ((StartY) >> sheight) * dstPitch;
2272 for (int y = (StartY) >> sheight; y <= (StartY + 64) >> sheight; y++) {
2273 if (pixelsize == 1) {
2274 for (int x = 0; x < (show_size >> swidth); x++) {
2275 int color = x >> pos_shift;
2276 int color_i = color << color_shift;
2277 ptr[x] = color_i;
2278 }
2279 }
2280 else if (pixelsize == 2) {
2281 for (int x = 0; x < (show_size >> swidth); x++) {
2282 int color = x >> pos_shift;
2283 int color_i = color << color_shift;
2284 reinterpret_cast<uint16_t *>(ptr)[x] = color_i;
2285 }
2286 }
2287 else { // pixelsize == 4 float
2288 for (int x = 0; x < (show_size >> swidth); x++) {
2289 int color = x >> pos_shift;
2290 float color_f = color / 255.0f;
2291 reinterpret_cast<float *>(ptr)[x] = color_f;
2292 }
2293 }
2294 ptr += dstPitch;
2295 }
2296 }
2297 else {
2298 if (!isGrey) {
2299 // UV gradients plus danger zones
2300 for (int gradient_upper_lower = 0; gradient_upper_lower < 2; gradient_upper_lower++)
2301 {
2302 // Draw upper and lower gradient
2303 // upper: x=0-16, R=G=255, B=0; x=128, R=G=B=0; x=240-255, R=G=0, B=255
2304 // lower: x=0-16, R=0, G=B=255; x=128, R=G=B=0; x=240-255, R=255, G=B=0
2305 const int color1_upper_lower_gradient[2][3] = { { 210 / 2, 16 + 112 / 2, 128 },{ 170 / 2, 128, 16 + 112 / 2 } };
2306 const int color2_upper_lower_gradient[2][3] = { { 41 / 2, 240 - 112 / 2, 128 },{ 81 / 2, 128, 240 - 112 / 2 } };
2307 float color1_upper_lower_gradient_f[2][3] = { { c8tof(210 / 2), uv8tof(16 + 112 / 2), uv8tof(128) },{ c8tof(170 / 2), uv8tof(128), uv8tof(16 + 112 / 2) } };
2308 float color2_upper_lower_gradient_f[2][3] = { { c8tof(41 / 2), uv8tof(240 - 112 / 2), uv8tof(128) },{ c8tof(81 / 2), uv8tof(128), uv8tof(240 - 112 / 2) } };
2309 int color = color1_upper_lower_gradient[gradient_upper_lower][p];
2310 int color_i = color << color_shift;
2311 float color_f = color1_upper_lower_gradient_f[gradient_upper_lower][p];
2312
2313 int color2 = color2_upper_lower_gradient[gradient_upper_lower][p];
2314 int color2_i = color2 << color_shift;
2315 float color2_f = color2_upper_lower_gradient_f[gradient_upper_lower][p];;
2316
2317 // upper only for planar U and Y
2318 if (plane == PLANAR_V && gradient_upper_lower == 0)
2319 continue;
2320 // lower only for planar V and Y
2321 if (plane == PLANAR_U && gradient_upper_lower == 1)
2322 continue;
2323 int StartY = gradient_upper_lower == 0 ? 64 + 16 : 128 + 32;
2324 ptr = pdstb + ((StartY) >> sheight) * dstPitch;
2325 // we are drawing at the 64th relative line as well.
2326 for (int y = (StartY) >> sheight; y <= (StartY + 64) >> sheight; y++) {
2327 int x = 0;
2328 // 0..15, (scaled) left danger area
2329 const int left_limit = ((16 << pos_shift) >> swidth) - 1;
2330 if (pixelsize == 1) {
2331 for (; x < left_limit; x++)
2332 ptr[x] = color_i;
2333 }
2334 else if (pixelsize == 2) {
2335 for (; x < left_limit; x++)
2336 reinterpret_cast<uint16_t*>(ptr)[x] = color_i;
2337 }
2338 else { // float
2339 for (; x < left_limit; x++)
2340 reinterpret_cast<float*>(ptr)[x] = color_f;
2341 }
2342
2343 if (plane == PLANAR_Y) {
2344 // from 16 to middle point
2345 if (pixelsize == 1) {
2346 for (; x <= show_middle_pos; x++) {
2347 int color3 =
2348 (gradient_upper_lower == 0) ?
2349 (((show_middle_pos - x) * 15) >> 3) >> pos_shift : // *1.875
2350 ((show_middle_pos - x) * 99515) >> 16 >> pos_shift; // *1.518
2351 int color3_i = color3 << color_shift;
2352 ptr[x] = color3_i;
2353 }
2354 }
2355 else if (pixelsize == 2) {
2356 for (; x <= show_middle_pos; x++) {
2357 int color3 =
2358 (gradient_upper_lower == 0) ?
2359 (((show_middle_pos - x) * 15) >> 3) >> pos_shift : // *1.875
2360 ((show_middle_pos - x) * 99515) >> 16 >> pos_shift; // *1.518
2361 int color3_i = color3 << color_shift;
2362 reinterpret_cast<uint16_t*>(ptr)[x] = color3_i;
2363 }
2364 }
2365 else { // float
2366 for (; x <= show_middle_pos; x++) {
2367 int color3 =
2368 (gradient_upper_lower == 0) ?
2369 (((show_middle_pos - x) * 15) >> 3) >> pos_shift : // *1.875
2370 ((show_middle_pos - x) * 99515) >> 16 >> pos_shift; // *1.518
2371 float color3_f = color3 / 255.0f; // no shift this is Y
2372 reinterpret_cast<float*>(ptr)[x] = color3_f;
2373 }
2374 }
2375 }
2376
2377 // Y: from middle point to white point
2378 // other plane: gradient
2379 if (plane == PLANAR_Y) {
2380 if (pixelsize == 1) {
2381 for (; x <= (240 << pos_shift) >> swidth; x++) {
2382 int color4 =
2383 (gradient_upper_lower == 0) ?
2384 ((x - show_middle_pos) * 24001) >> 16 >> pos_shift : // *0.366
2385 ((x - show_middle_pos) * 47397) >> 16 >> pos_shift; // *0.723
2386 int color4_i = color4 << color_shift;
2387 ptr[x] = color4_i;
2388 }
2389 }
2390 else if (pixelsize == 2) {
2391 for (; x <= (240 << pos_shift) >> swidth; x++) {
2392 int color4 =
2393 (gradient_upper_lower == 0) ?
2394 ((x - show_middle_pos) * 24001) >> 16 >> pos_shift : // *0.366
2395 ((x - show_middle_pos) * 47397) >> 16 >> pos_shift; // *0.723
2396 int color4_i = color4 << color_shift;
2397 reinterpret_cast<uint16_t*>(ptr)[x] = color4_i;
2398 }
2399 }
2400 else { // float
2401 for (; x <= (240 << pos_shift) >> swidth; x++) {
2402 int color4 =
2403 (gradient_upper_lower == 0) ?
2404 ((x - show_middle_pos) * 24001) >> 16 >> pos_shift : // *0.366
2405 ((x - show_middle_pos) * 47397) >> 16 >> pos_shift; // *0.723
2406 float color4_f = color4 / 255.0f; // no shift, this is Y
2407 reinterpret_cast<float*>(ptr)[x] = color4_f;
2408 }
2409 }
2410 }
2411 else {
2412 // plane == U or V
2413 if (pixelsize == 1) {
2414 for (; x <= (240 << pos_shift) >> swidth; x++) {
2415 int color4 = (x << swidth) >> pos_shift;
2416 int color4_i = color4 << color_shift;
2417 ptr[x] = color4_i;
2418 }
2419 }
2420 else if (pixelsize == 2) {
2421 for (; x <= (240 << pos_shift) >> swidth; x++) {
2422 int color4 = (x << swidth) >> pos_shift;
2423 int color4_i = color4 << color_shift;
2424 reinterpret_cast<uint16_t*>(ptr)[x] = color4_i;
2425 }
2426 }
2427 else { // float
2428 for (; x <= (240 << pos_shift) >> swidth; x++) {
2429 int color4 = (x << swidth) >> pos_shift;
2430 reinterpret_cast<float*>(ptr)[x] = uv8tof(color4);
2431 }
2432 }
2433 }
2434
2435 if (pixelsize == 1) {
2436 for (; x < (show_size >> swidth); x++)
2437 ptr[x] = color2_i;
2438 }
2439 else if (pixelsize == 2) {
2440 for (; x < (show_size >> swidth); x++)
2441 reinterpret_cast<uint16_t*>(ptr)[x] = color2_i;
2442 }
2443 else { // float
2444 for (; x < (show_size >> swidth); x++)
2445 reinterpret_cast<float*>(ptr)[x] = color2_f;
2446 }
2447
2448 ptr += dstPitch;
2449 } // for y gradient draw
2450 } // gradient for upper lower
2451 }
2452 } // gradients for RGB/UV
2453 } // if markers
2454 } // planes for
2455
2456 // Draw dotted centerline
2457 // YUV: only 1 plane (PLANAR_Y)
2458
3/4
✗ Branch 533 → 534 not taken.
✓ Branch 533 → 535 taken 2 times.
✓ Branch 536 → 518 taken 1 time.
✓ Branch 536 → 537 taken 1 time.
2 for (int p = 0; p < (RGB ? 3 : 1); p++) {
2459 1 const int plane = planes[p];
2460
2461 1 int color = 128; // also good for RGB
2462 1 int color_i = color << color_shift;
2463 1 float color_f = 0.5f;
2464
2465
1/2
✓ Branch 519 → 520 taken 1 time.
✗ Branch 519 → 600 not taken.
1 const int dstPitch = dst->GetPitch(plane);
2466
2467
1/2
✓ Branch 521 → 522 taken 1 time.
✗ Branch 521 → 600 not taken.
1 unsigned char* pdstb = dst->GetWritePtr(plane);
2468 1 pdstb += (xstart * pixelsize); // next to the original clip (if kept), working only on Y plane: no ">> swidth" needed
2469 1 BYTE* ptr = pdstb;
2470
2471
1/2
✗ Branch 522 → 523 not taken.
✓ Branch 522 → 532 taken 1 time.
1 if (markers) {
2472 // omit centerline if markers == false
2473 // height of 64, 16 pixels between
2474 // we are drawing at the 64th/224th relative line as well.
2475 for (int y = 0; y <= 64 + (planecount - 1) * (16 + 64); y++) {
2476 if ((y & 3) > 1) {
2477 if (pixelsize == 1) ptr[show_middle_pos] = color_i;
2478 else if (pixelsize == 2) reinterpret_cast<uint16_t*>(ptr)[show_middle_pos] = color_i;
2479 else reinterpret_cast<float*>(ptr)[show_middle_pos] = color_f;
2480
2481 }
2482 ptr += dstPitch;
2483 }
2484 }
2485 }
2486
2487
3/4
✗ Branch 591 → 592 not taken.
✓ Branch 591 → 593 taken 2 times.
✓ Branch 594 → 538 taken 1 time.
✓ Branch 594 → 595 taken 1 time.
2 for (int p = 0; p < (RGB ? 3 : 1); p++) {
2488 1 const int plane = planes[p];
2489
2490
1/2
✓ Branch 539 → 540 taken 1 time.
✗ Branch 539 → 600 not taken.
1 const int dstPitch = dst->GetPitch(plane);
2491
2492
1/2
✓ Branch 541 → 542 taken 1 time.
✗ Branch 541 → 600 not taken.
1 unsigned char* pdstb = dst->GetWritePtr(plane);
2493 1 pdstb += (xstart * pixelsize); // next to the original clip (if kept), working only on Y plane: no ">> swidth" needed
2494
2495 // have to draw up to three parts: Y or Y,U,V or R,G,B
2496
2/2
✓ Branch 589 → 543 taken 3 times.
✓ Branch 589 → 590 taken 1 time.
4 for (int n = 0; n < planecount; n++) {
2497
2498 // Draw histograms
2499
2500 // total pixel count must be divided by subsampling factors for U and V
2501
1/2
✓ Branch 544 → 545 taken 3 times.
✗ Branch 544 → 600 not taken.
3 int src_width = src->GetRowSize(planes[n]) / pixelsize;
2502
1/2
✓ Branch 546 → 547 taken 3 times.
✗ Branch 546 → 600 not taken.
3 int src_height = src->GetHeight(planes[n]);
2503
2504
1/2
✓ Branch 547 → 548 taken 3 times.
✗ Branch 547 → 600 not taken.
3 const uint32_t clampval = (int)((src_width*src_height)*option.AsDblDef(100.0) / 100.0); // Population limit % factor
2505 3 uint32_t maxval = 0;
2506 uint32_t *hist;
2507
2508 3 hist = histPlanes[n];
2509
2/2
✓ Branch 553 → 549 taken 768 times.
✓ Branch 553 → 554 taken 3 times.
771 for (int i = 0; i < show_size; i++) {
2510
1/2
✗ Branch 549 → 550 not taken.
✓ Branch 549 → 551 taken 768 times.
768 if (hist[i] > clampval) hist[i] = clampval;
2511 768 maxval = max(hist[i], maxval);
2512 }
2513
2514 // factor 0%: maxval may stay at 0.
2515
1/2
✓ Branch 554 → 555 taken 3 times.
✗ Branch 554 → 556 not taken.
3 float scale = maxval == 0 ? 64.0f : float(64.0 / maxval);
2516
2517
1/2
✗ Branch 557 → 558 not taken.
✓ Branch 557 → 559 taken 3 times.
3 int color = RGB ? 255 : 235; // also good for RGB
2518
1/2
✗ Branch 560 → 561 not taken.
✓ Branch 560 → 562 taken 3 times.
3 int color_i = RGB ? (int)(color * color_shift_factor + 0.5f) : color << color_shift;
2519 3 float color_f = color / 255.0f;
2520
2521 int Y_pos;
2522
3/4
✓ Branch 563 → 564 taken 1 time.
✓ Branch 563 → 568 taken 1 time.
✓ Branch 563 → 572 taken 1 time.
✗ Branch 563 → 576 not taken.
3 switch (n) { // n: YUV 012, GBR 012
2523
1/2
✗ Branch 564 → 565 not taken.
✓ Branch 564 → 566 taken 1 time.
1 case 0: Y_pos = RGB ? 128 + 16 : 64 + 0; break; // Y or G
2524
1/2
✗ Branch 568 → 569 not taken.
✓ Branch 568 → 570 taken 1 time.
1 case 1: Y_pos = RGB ? 192 + 32 : 128 + 16; break; // U or B
2525
1/2
✗ Branch 572 → 573 not taken.
✓ Branch 572 → 574 taken 1 time.
1 case 2: Y_pos = RGB ? 64 + 0 : 192 + 32; break; // V or R
2526 }
2527
2528
2/2
✓ Branch 587 → 577 taken 768 times.
✓ Branch 587 → 588 taken 3 times.
771 for (int x = 0; x < show_size; x++) {
2529 768 float scaled_h = (float)hist[x] * scale;
2530 768 int h = Y_pos - min((int)scaled_h, 64) + 1;
2531
2532 768 uint8_t *ptr = pdstb + (Y_pos + 1) * dstPitch;
2533
2534 // Start from below the baseline
2535
2/2
✓ Branch 585 → 579 taken 768 times.
✓ Branch 585 → 586 taken 768 times.
1536 for (int y = Y_pos + 1; y > h; y--) {
2536
1/2
✓ Branch 579 → 580 taken 768 times.
✗ Branch 579 → 581 not taken.
768 if (pixelsize == 1) ptr[x] = color_i;
2537 else if (pixelsize == 2) reinterpret_cast<uint16_t *>(ptr)[x] = color_i;
2538 else reinterpret_cast<float *>(ptr)[x] = color_f;
2539 768 ptr -= dstPitch;
2540 }
2541
2542 }
2543 }
2544 }
2545 }
2546
2547
1/2
✓ Branch 595 → 596 taken 1 time.
✗ Branch 595 → 600 not taken.
1 env->Free(histPlane1);
2548
2549 1 return dst;
2550 1 }
2551
2552
2553 2 void Histogram::ClassicLUTInit()
2554 {
2555
1/2
✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 4 not taken.
2 int internal_bits_per_pixel = (pixelsize == 4) ? 16 : bits_per_pixel; // 16bit histogram simulation for float
2556
2557 2 int tv_range_low = 16 << (internal_bits_per_pixel - 8); // 16
2558 2 int tv_range_hi_luma = 235 << (internal_bits_per_pixel - 8); // 16-235
2559 2 int range_luma = tv_range_hi_luma - tv_range_low; // 219
2560 // exptab: population count within a line -> brigtness mapping
2561 // exptab index (population) is maximized at 255 during the actual drawing
2562 2 exptab.resize(256);
2563 2 const double K = log(0.5 / 219) / 255.0; // approx -1/42
2564 2 const int limit68 = 68 << (internal_bits_per_pixel - 8);
2565 // exptab: pixel values for final drawing
2566 2 exptab[0] = tv_range_low;
2567
2/2
✓ Branch 13 → 8 taken 508 times.
✓ Branch 13 → 14 taken 2 times.
510 for (int i = 1; i < 255; i++) {
2568 508 exptab[i] = uint16_t(tv_range_low + 0.5 + range_luma * (1 - exp(i*K))); // 16.5 + 219*
2569
2/2
✓ Branch 10 → 11 taken 98 times.
✓ Branch 10 → 12 taken 410 times.
508 if (exptab[i] <= tv_range_hi_luma - limit68)
2570 98 E167 = i; // index of last value less than... for drawing lower extremes
2571 }
2572 2 exptab[255] = tv_range_hi_luma;
2573 2 }
2574
2575 3 PVideoFrame Histogram::DrawModeClassic(int n, IScriptEnvironment* env)
2576 {
2577
2578 3 int show_size = 1 << show_bits;
2579
2580 3 int hist_tv_range_low = 16 << (show_bits - 8); // 16
2581 3 int hist_tv_range_hi_luma = 235 << (show_bits - 8); // 16-235
2582 3 int hist_range_luma = hist_tv_range_hi_luma - hist_tv_range_low; // 219
2583 3 int hist_mid_range_luma = (hist_range_luma + 1) / 2 + hist_tv_range_low - 1; // in Classic Avisynth somehow 124 was fixed for this
2584 // 235-16 = 219 / 2 => 110; 110 + 16 - 1 = 125.0
2585
2586
1/2
✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 4 not taken.
3 int internal_bits_per_pixel = (pixelsize == 4) ? 16 : bits_per_pixel; // 16bit histogram simulation for float
2587
2588 3 int middle_chroma = 1 << (internal_bits_per_pixel - 1); // 128
2589
2590 3 const int source_width = origwidth;
2591
2/2
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 2 times.
3 const int xstart = keepsource ? origwidth : 0; // drawing starts at this column
2592
2593
1/2
✓ Branch 9 → 10 taken 3 times.
✗ Branch 9 → 276 not taken.
3 PVideoFrame src = child->GetFrame(n, env);
2594
1/2
✓ Branch 11 → 12 taken 3 times.
✗ Branch 11 → 274 not taken.
3 const BYTE* srcp = src->GetReadPtr();
2595
1/2
✓ Branch 13 → 14 taken 3 times.
✗ Branch 13 → 274 not taken.
3 const int srcpitch = src->GetPitch();
2596
2597
1/2
✓ Branch 14 → 15 taken 3 times.
✗ Branch 14 → 274 not taken.
3 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
2598
1/2
✓ Branch 16 → 17 taken 3 times.
✗ Branch 16 → 272 not taken.
3 BYTE* pdst = dst->GetWritePtr();
2599
1/2
✓ Branch 18 → 19 taken 3 times.
✗ Branch 18 → 272 not taken.
3 const int dstpitch = dst->GetPitch();
2600
2601
2/2
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 31 taken 2 times.
3 if (keepsource) {
2602
6/12
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 272 not taken.
✓ Branch 23 → 24 taken 1 time.
✗ Branch 23 → 272 not taken.
✓ Branch 25 → 26 taken 1 time.
✗ Branch 25 → 272 not taken.
✓ Branch 27 → 28 taken 1 time.
✗ Branch 27 → 272 not taken.
✓ Branch 29 → 30 taken 1 time.
✗ Branch 29 → 272 not taken.
✓ Branch 30 → 31 taken 1 time.
✗ Branch 30 → 272 not taken.
1 env->BitBlt(pdst, dst->GetPitch(), src->GetReadPtr(), src->GetPitch(), src->GetRowSize(), src->GetHeight());
2603 }
2604
2/4
✓ Branch 31 → 32 taken 3 times.
✗ Branch 31 → 272 not taken.
✓ Branch 32 → 33 taken 3 times.
✗ Branch 32 → 227 not taken.
3 if (vi.IsPlanar()) {
2605
2/2
✓ Branch 33 → 34 taken 1 time.
✓ Branch 33 → 60 taken 2 times.
3 if (keepsource) {
2606
7/14
✓ Branch 35 → 36 taken 1 time.
✗ Branch 35 → 271 not taken.
✓ Branch 37 → 38 taken 1 time.
✗ Branch 37 → 271 not taken.
✓ Branch 39 → 40 taken 1 time.
✗ Branch 39 → 271 not taken.
✓ Branch 41 → 42 taken 1 time.
✗ Branch 41 → 271 not taken.
✓ Branch 43 → 44 taken 1 time.
✗ Branch 43 → 271 not taken.
✓ Branch 45 → 46 taken 1 time.
✗ Branch 45 → 271 not taken.
✓ Branch 46 → 47 taken 1 time.
✗ Branch 46 → 271 not taken.
1 env->BitBlt(dst->GetWritePtr(PLANAR_U), dst->GetPitch(PLANAR_U), src->GetReadPtr(PLANAR_U), src->GetPitch(PLANAR_U), src->GetRowSize(PLANAR_U), src->GetHeight(PLANAR_U));
2607
7/14
✓ Branch 48 → 49 taken 1 time.
✗ Branch 48 → 271 not taken.
✓ Branch 50 → 51 taken 1 time.
✗ Branch 50 → 271 not taken.
✓ Branch 52 → 53 taken 1 time.
✗ Branch 52 → 271 not taken.
✓ Branch 54 → 55 taken 1 time.
✗ Branch 54 → 271 not taken.
✓ Branch 56 → 57 taken 1 time.
✗ Branch 56 → 271 not taken.
✓ Branch 58 → 59 taken 1 time.
✗ Branch 58 → 271 not taken.
✓ Branch 59 → 60 taken 1 time.
✗ Branch 59 → 271 not taken.
1 env->BitBlt(dst->GetWritePtr(PLANAR_V), dst->GetPitch(PLANAR_V), src->GetReadPtr(PLANAR_V), src->GetPitch(PLANAR_V), src->GetRowSize(PLANAR_V), src->GetHeight(PLANAR_V));
2608 }
2609
2610 // luma
2611
1/2
✓ Branch 61 → 62 taken 3 times.
✗ Branch 61 → 271 not taken.
3 const int height = src->GetHeight(PLANAR_Y);
2612
2613 3 std::vector<int> hist;
2614
1/2
✓ Branch 63 → 64 taken 3 times.
✗ Branch 63 → 269 not taken.
3 hist.resize(1ULL << show_bits);
2615
2616
2/2
✓ Branch 160 → 65 taken 6 times.
✓ Branch 160 → 161 taken 3 times.
9 for (int y = 0; y<height; ++y) {
2617 6 std::fill(hist.begin(), hist.end(), 0);
2618 // accumulate line population
2619
1/2
✓ Branch 74 → 75 taken 6 times.
✗ Branch 74 → 79 not taken.
6 if(pixelsize==1) {
2620 // 8 bit clip into 8,9,... bit histogram
2621 6 int invshift = show_bits - 8;
2622
2/2
✓ Branch 78 → 76 taken 48 times.
✓ Branch 78 → 96 taken 6 times.
54 for (int x = 0; x<source_width; ++x) {
2623 48 hist[srcp[x] << invshift]++;
2624 }
2625 }
2626 else if (pixelsize == 2) {
2627 const uint16_t *srcp16 = reinterpret_cast<const uint16_t *>(srcp);
2628 int shift = bits_per_pixel - show_bits;
2629 int max_show_pixel_value = show_size - 1;
2630 if (shift < 0) {
2631 // 10 bit clip into 11 bit histogram
2632 int invshift = -shift;
2633 for (int x = 0; x < source_width; x++) {
2634 hist[min(srcp16[x] << invshift, max_show_pixel_value)]++;
2635 }
2636 } else {
2637 // e.g.10 bit clip into 8-9-10 bit histogram
2638 for (int x = 0; x < source_width; x++) {
2639 hist[min(srcp16[x] >> shift, max_show_pixel_value)]++;
2640 }
2641 }
2642 }
2643 else // pixelsize == 4
2644 {
2645 // float
2646 const float *srcp32 = reinterpret_cast<const float *>(srcp);
2647 const float multiplier = (float)(show_size - 1);
2648 for (int x = 0; x < source_width; x++) {
2649 hist[(intptr_t)(clamp(srcp32[x], 0.0f, 1.0f)*multiplier + 0.5f)]++; // luma, no shift needed
2650 }
2651 }
2652 // accumulate end
2653 6 BYTE* const q = pdst + xstart * pixelsize; // write to frame
2654
1/2
✗ Branch 96 → 97 not taken.
✓ Branch 96 → 139 taken 6 times.
6 if (markers) {
2655 if (pixelsize == 1) {
2656 for (int x = 0; x < show_size; ++x) {
2657 if (x<hist_tv_range_low || x == hist_mid_range_luma || x>hist_tv_range_hi_luma) {
2658 q[x] = (BYTE)exptab[min(E167, hist[x])] + 68; // brighter danger zone
2659 }
2660 else {
2661 q[x] = (BYTE)exptab[min(255, hist[x])];
2662 }
2663 }
2664 }
2665 else if (pixelsize == 2) {
2666 uint16_t *dstp16 = reinterpret_cast<uint16_t *>(q);
2667 for (int x = 0; x < show_size; ++x) {
2668 int h = hist[x];
2669 if (x<hist_tv_range_low || x == hist_mid_range_luma || x>hist_tv_range_hi_luma) {
2670 dstp16[x] = exptab[min(E167, h)] + (68 << (bits_per_pixel - 8));
2671 }
2672 else {
2673 dstp16[x] = exptab[min(255, h)];
2674 }
2675 }
2676 }
2677 else { // pixelsize == 4
2678 float *dstp32 = reinterpret_cast<float *>(q);
2679 for (int x = 0; x < show_size; ++x) {
2680 int h = hist[x];
2681 if (x<hist_tv_range_low || x == hist_mid_range_luma || x>hist_tv_range_hi_luma) {
2682 dstp32[x] = (exptab[min(E167, h)] + (68 << (internal_bits_per_pixel - 8))) / 65535.0f; // fake 0..65535 to 0..1.0
2683 }
2684 else {
2685 dstp32[x] = exptab[min(255, h)] / 65535.0f;
2686 }
2687 }
2688 }
2689 }
2690 else {
2691
1/2
✓ Branch 139 → 140 taken 6 times.
✗ Branch 139 → 146 not taken.
6 if (pixelsize == 1) {
2692
2/2
✓ Branch 145 → 141 taken 1536 times.
✓ Branch 145 → 159 taken 6 times.
1542 for (int x = 0; x < show_size; ++x)
2693 1536 q[x] = (BYTE)exptab[min(255, hist[x])];
2694 }
2695 else if (pixelsize == 2) {
2696 uint16_t *dstp16 = reinterpret_cast<uint16_t *>(q);
2697 for (int x = 0; x < show_size; ++x) {
2698 int h = hist[x];
2699 dstp16[x] = exptab[min(255, h)];
2700 }
2701 }
2702 else { // pixelsize == 4
2703 float *dstp32 = reinterpret_cast<float *>(q);
2704 for (int x = 0; x < show_size; ++x) {
2705 int h = hist[x];
2706 dstp32[x] = exptab[min(255, h)] / 65535.0f; // fake 0..65535 to 0..1.0
2707 }
2708 }
2709 }
2710 6 srcp += srcpitch;
2711 6 pdst += dstpitch;
2712 } // end of pixel accumulation + luma
2713
2714 // chroma
2715
1/2
✓ Branch 162 → 163 taken 3 times.
✗ Branch 162 → 269 not taken.
3 const int pitchUV = dst->GetPitch(PLANAR_U);
2716
2717
1/2
✗ Branch 163 → 164 not taken.
✓ Branch 163 → 225 taken 3 times.
3 if (pitchUV != 0) {
2718 const int subs = vi.GetPlaneWidthSubsampling(PLANAR_U);
2719 const int fact = 1<<subs;
2720
2721 BYTE* p2 = dst->GetWritePtr(PLANAR_U) + ((xstart*pixelsize) >> subs); // put it on the right
2722 BYTE* p3 = dst->GetWritePtr(PLANAR_V) + ((xstart*pixelsize) >> subs); // put it on the right
2723
2724 // if markers==false parameter, keep neutral coloring
2725 const uint16_t color_u_offlimit8 = markers ? 16 : 128;
2726 const uint16_t color_v_offlimit8 = markers ? 160 : 128;
2727 const uint16_t color_u_centermark8 = markers ? 160 : 128;
2728 const uint16_t color_v_centermark8 = markers ? 16 : 128;
2729
2730 const uint16_t color_u_offlimit = color_u_offlimit8 << (internal_bits_per_pixel - 8);
2731 const uint16_t color_v_offlimit = color_v_offlimit8 << (internal_bits_per_pixel - 8);
2732 const uint16_t color_u_centermark = color_u_centermark8 << (internal_bits_per_pixel - 8);
2733 const uint16_t color_v_centermark = color_v_centermark8 << (internal_bits_per_pixel - 8);
2734
2735 const float color_u_offlimit_f = uv8tof(color_u_offlimit8);
2736 const float color_v_offlimit_f = uv8tof(color_v_offlimit8);
2737 const float color_u_centermark_f = uv8tof(color_u_centermark8);
2738 const float color_v_centermark_f = uv8tof(color_v_centermark8);
2739 const float middle_chroma_f = uv8tof(128);
2740
2741 const int height = src->GetHeight(PLANAR_U);
2742 for (int y2 = 0; y2<height; ++y2) {
2743 if(pixelsize==1) {
2744 for (int x = 0; x<show_size; x += fact) {
2745 if (x<hist_tv_range_low || x>hist_tv_range_hi_luma) {
2746 p2[x >> subs] = (BYTE)color_u_offlimit8;
2747 p3[x >> subs] = (BYTE)color_v_offlimit8;
2748 } else if (x==hist_mid_range_luma) {
2749 p2[x >> subs] = (BYTE)color_u_centermark8;
2750 p3[x >> subs] = (BYTE)color_v_centermark8;
2751 } else {
2752 p2[x >> subs] = 128;
2753 p3[x >> subs] = 128;
2754 }
2755 }
2756 }
2757 else if (pixelsize == 2) {
2758 for (int x = 0; x<show_size; x += fact) {
2759 if (x<hist_tv_range_low || x>hist_tv_range_hi_luma) {
2760 reinterpret_cast<uint16_t *>(p2)[x >> subs] = color_u_offlimit;
2761 reinterpret_cast<uint16_t *>(p3)[x >> subs] = color_v_offlimit;
2762 } else if (x==hist_mid_range_luma) {
2763 reinterpret_cast<uint16_t *>(p2)[x >> subs] = color_u_centermark;
2764 reinterpret_cast<uint16_t *>(p3)[x >> subs] = color_v_centermark;
2765 } else {
2766 reinterpret_cast<uint16_t *>(p2)[x >> subs] = middle_chroma;
2767 reinterpret_cast<uint16_t *>(p3)[x >> subs] = middle_chroma;
2768 }
2769 }
2770 } else { // pixelsize==4
2771 for (int x = 0; x<show_size; x += fact) {
2772 if (x<hist_tv_range_low || x>hist_tv_range_hi_luma) {
2773 reinterpret_cast<float *>(p2)[x >> subs] = color_u_offlimit_f;
2774 reinterpret_cast<float *>(p3)[x >> subs] = color_v_offlimit_f;
2775 } else if (x==hist_mid_range_luma) {
2776 reinterpret_cast<float *>(p2)[x >> subs] = color_u_centermark_f;
2777 reinterpret_cast<float *>(p3)[x >> subs] = color_v_centermark_f;
2778 } else {
2779 reinterpret_cast<float *>(p2)[x >> subs] = middle_chroma_f;
2780 reinterpret_cast<float *>(p3)[x >> subs] = middle_chroma_f;
2781 }
2782 }
2783
2784 }
2785 p2 += pitchUV;
2786 p3 += pitchUV;
2787 }
2788 }
2789 3 } else {
2790 const int pitch = dst->GetPitch();
2791 for (int y = 0; y<src->GetHeight(); ++y) { // YUY2
2792 int hist[256] = { 0 };
2793 for (int x = 0; x<source_width; ++x) {
2794 hist[srcp[x*2]]++;
2795 }
2796 BYTE* const q = pdst + xstart*2;
2797 if (markers) {
2798 for (int x = 0; x < 256; x += 2) {
2799 if (x < 16 || x>235) {
2800 q[x * 2 + 0] = (BYTE)exptab[min(E167, hist[x])] + 68;
2801 q[x * 2 + 1] = 16;
2802 q[x * 2 + 2] = (BYTE)exptab[min(E167, hist[x + 1])] + 68;
2803 q[x * 2 + 3] = 160;
2804 }
2805 else if (x == 124) {
2806 q[x * 2 + 0] = (BYTE)exptab[min(E167, hist[x])] + 68;
2807 q[x * 2 + 1] = 160;
2808 q[x * 2 + 2] = (BYTE)exptab[min(255, hist[x + 1])];
2809 q[x * 2 + 3] = 16;
2810 }
2811 else {
2812 q[x * 2 + 0] = (BYTE)exptab[min(255, hist[x])];
2813 q[x * 2 + 1] = 128;
2814 q[x * 2 + 2] = (BYTE)exptab[min(255, hist[x + 1])];
2815 q[x * 2 + 3] = 128;
2816 }
2817 }
2818 }
2819 else {
2820 for (int x = 0; x < 256; x += 2) {
2821 q[x * 2 + 0] = (BYTE)exptab[min(255, hist[x])];
2822 q[x * 2 + 1] = 128;
2823 q[x * 2 + 2] = (BYTE)exptab[min(255, hist[x + 1])];
2824 q[x * 2 + 3] = 128;
2825 }
2826 }
2827 pdst += pitch;
2828 srcp += srcpitch;
2829 }
2830 }
2831 3 return dst;
2832 3 }
2833
2834
2835 1 AVSValue __cdecl Histogram::Create(AVSValue args, void*, IScriptEnvironment* env)
2836 {
2837
2/4
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 293 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 293 not taken.
1 const char* st_m = args[1].AsString("classic");
2838
2839 1 Mode mode = ModeClassic;
2840
2841
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1 time.
1 if (!lstrcmpi(st_m, "classic"))
2842 mode = ModeClassic;
2843
2844
1/2
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 8 not taken.
1 if (!lstrcmpi(st_m, "levels"))
2845 1 mode = ModeLevels;
2846
2847
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 1 time.
1 if (!lstrcmpi(st_m, "color"))
2848 mode = ModeColor;
2849
2850
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 1 time.
1 if (!lstrcmpi(st_m, "color2"))
2851 mode = ModeColor2;
2852
2853
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 1 time.
1 if (!lstrcmpi(st_m, "luma"))
2854 mode = ModeLuma;
2855
2856
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 1 time.
1 if (!lstrcmpi(st_m, "stereoY8"))
2857 mode = ModeStereoY8;
2858
2859
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 1 time.
1 if (!lstrcmpi(st_m, "stereo"))
2860 mode = ModeStereo;
2861
2862
1/2
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 1 time.
1 if (!lstrcmpi(st_m, "stereooverlay"))
2863 mode = ModeOverlay;
2864
2865
1/2
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 1 time.
1 if (!lstrcmpi(st_m, "audiolevels"))
2866 mode = ModeAudioLevels;
2867
2868
3/6
✓ Branch 22 → 23 taken 1 time.
✗ Branch 22 → 190 not taken.
✓ Branch 23 → 24 taken 1 time.
✗ Branch 23 → 190 not taken.
✓ Branch 25 → 26 taken 1 time.
✗ Branch 25 → 188 not taken.
1 const VideoInfo& vi_orig = args[0].AsClip()->GetVideoInfo();
2869
2870 histogram_color2_params color2_params;
2871
2/4
✓ Branch 27 → 28 taken 1 time.
✗ Branch 27 → 293 not taken.
✓ Branch 28 → 29 taken 1 time.
✗ Branch 28 → 293 not taken.
1 const char *graticule_str = args[7].AsString("on"); // ON: old vectorscopes always drew limits/danger zones
2872
2873 // Use the lstrcmpi macro from your compatibility header
2874
1/2
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 1 time.
1 if (lstrcmpi(graticule_str, "auto") == 0) {
2875 color2_params.graticule_type = histogram_color2_params::GRATICULE_AUTO;
2876 }
2877
1/2
✓ Branch 31 → 32 taken 1 time.
✗ Branch 31 → 33 not taken.
1 else if (lstrcmpi(graticule_str, "on") == 0) {
2878 1 color2_params.graticule_type = histogram_color2_params::GRATICULE_ON;
2879 }
2880 else if (lstrcmpi(graticule_str, "off") == 0) {
2881 color2_params.graticule_type = histogram_color2_params::GRATICULE_OFF;
2882 }
2883 else {
2884 env->ThrowError("Histogram: 'graticule' must be \"on\", \"off\", or \"auto\".");
2885 }
2886
2887
2/4
✓ Branch 36 → 37 taken 1 time.
✗ Branch 36 → 293 not taken.
✓ Branch 37 → 38 taken 1 time.
✗ Branch 37 → 293 not taken.
1 color2_params.targets = args[8].AsBool(false); // The 6 75% RGB squares
2888
2/4
✓ Branch 38 → 39 taken 1 time.
✗ Branch 38 → 293 not taken.
✓ Branch 39 → 40 taken 1 time.
✗ Branch 39 → 293 not taken.
1 color2_params.axes = args[9].AsBool(false); // horizontal and vertical axes
2889
2/4
✓ Branch 40 → 41 taken 1 time.
✗ Branch 40 → 293 not taken.
✓ Branch 41 → 42 taken 1 time.
✗ Branch 41 → 293 not taken.
1 color2_params.iq = args[10].AsBool(false); // +/-I and +Q targets
2890
2/4
✓ Branch 42 → 43 taken 1 time.
✗ Branch 42 → 293 not taken.
✓ Branch 43 → 44 taken 1 time.
✗ Branch 43 → 293 not taken.
1 color2_params.iq_lines = args[11].AsBool(false); // 33 and 123 degree lines in the color2 mode
2891
2/4
✓ Branch 44 → 45 taken 1 time.
✗ Branch 44 → 293 not taken.
✓ Branch 45 → 46 taken 1 time.
✗ Branch 45 → 293 not taken.
1 color2_params.circle = args[12].AsBool(mode == ModeColor2 ? true : false); // circle in the color2 mode default
2892
2/4
✓ Branch 46 → 47 taken 1 time.
✗ Branch 46 → 293 not taken.
✓ Branch 47 → 48 taken 1 time.
✗ Branch 47 → 293 not taken.
1 color2_params.targets100 = args[13].AsBool(false); // The 6 100% RGB squares
2893
2894
4/12
✓ Branch 48 → 49 taken 1 time.
✗ Branch 48 → 54 not taken.
✓ Branch 49 → 50 taken 1 time.
✗ Branch 49 → 293 not taken.
✗ Branch 50 → 51 not taken.
✓ Branch 50 → 54 taken 1 time.
✗ Branch 51 → 52 not taken.
✗ Branch 51 → 293 not taken.
✗ Branch 52 → 53 not taken.
✗ Branch 52 → 54 not taken.
✗ Branch 55 → 56 not taken.
✓ Branch 55 → 165 taken 1 time.
1 if (mode == ModeLevels && vi_orig.IsRGB() && !vi_orig.IsPlanar()) {
2895 // as Levels can work for PlanarRGB, convert packed RGB to planar, then back
2896 // better that nothing
2897 AVSValue new_args[1] = { args[0].AsClip() };
2898 PClip clip;
2899 if (vi_orig.IsRGB24() || vi_orig.IsRGB48()) {
2900 clip = env->Invoke("ConvertToPlanarRGB", AVSValue(new_args, 1)).AsClip();
2901 }
2902 else if (vi_orig.IsRGB32() || vi_orig.IsRGB64()) {
2903 clip = env->Invoke("ConvertToPlanarRGBA", AVSValue(new_args, 1)).AsClip();
2904 }
2905
2906 Histogram* Result = new Histogram(clip, mode, args[2], args[3].AsInt(8), args[4].AsBool(true),
2907 args[5].AsBool(true),
2908 args[6].AsString(""), // matrix_name
2909 color2_params,
2910 env);
2911
2912 AVSValue new_args2[1] = { Result };
2913 if (vi_orig.IsRGB24()) {
2914 return env->Invoke("ConvertToRGB24", AVSValue(new_args2, 1)).AsClip();
2915 }
2916 else if (vi_orig.IsRGB48()) {
2917 return env->Invoke("ConvertToRGB48", AVSValue(new_args2, 1)).AsClip();
2918 }
2919 else if (vi_orig.IsRGB32()) {
2920 return env->Invoke("ConvertToRGB32", AVSValue(new_args2, 1)).AsClip();
2921 }
2922 else { // if (vi_orig.IsRGB64())
2923 return env->Invoke("ConvertToRGB64", AVSValue(new_args2, 1)).AsClip();
2924 }
2925 }
2926 else {
2927
3/6
✓ Branch 171 → 172 taken 1 time.
✗ Branch 171 → 290 not taken.
✓ Branch 176 → 177 taken 1 time.
✗ Branch 176 → 286 not taken.
✓ Branch 177 → 178 taken 1 time.
✗ Branch 177 → 286 not taken.
3 return new Histogram(args[0].AsClip(), mode, args[2], args[3].AsInt(8), args[4].AsBool(true),
2928
1/2
✓ Branch 169 → 170 taken 1 time.
✗ Branch 169 → 290 not taken.
1 args[5].AsBool(true), // markers
2929 2 args[6].AsString(""), // matrix_name
2930 color2_params,
2931
12/26
✓ Branch 165 → 166 taken 1 time.
✗ Branch 165 → 293 not taken.
✓ Branch 166 → 167 taken 1 time.
✗ Branch 166 → 290 not taken.
✓ Branch 167 → 168 taken 1 time.
✗ Branch 167 → 290 not taken.
✓ Branch 168 → 169 taken 1 time.
✗ Branch 168 → 290 not taken.
✓ Branch 170 → 171 taken 1 time.
✗ Branch 170 → 290 not taken.
✓ Branch 172 → 173 taken 1 time.
✗ Branch 172 → 290 not taken.
✓ Branch 173 → 174 taken 1 time.
✗ Branch 173 → 290 not taken.
✓ Branch 174 → 175 taken 1 time.
✗ Branch 174 → 289 not taken.
✓ Branch 175 → 176 taken 1 time.
✗ Branch 175 → 289 not taken.
✓ Branch 178 → 179 taken 1 time.
✗ Branch 178 → 284 not taken.
✓ Branch 179 → 180 taken 1 time.
✗ Branch 179 → 284 not taken.
✗ Branch 183 → 184 not taken.
✓ Branch 183 → 185 taken 1 time.
✗ Branch 290 → 291 not taken.
✗ Branch 290 → 292 not taken.
5 env);
2932 }
2933 }
2934