GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 24.7% 173 / 0 / 700
Functions: 29.4% 5 / 0 / 17
Branches: 13.0% 140 / 0 / 1074

filters/color.cpp
Line Branch Exec Source
1 // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al.
2 // http://avisynth.nl
3
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
17 // http://www.gnu.org/copyleft/gpl.html .
18 //
19 // Linking Avisynth statically or dynamically with other modules is making a
20 // combined work based on Avisynth. Thus, the terms and conditions of the GNU
21 // General Public License cover the whole combination.
22 //
23 // As a special exception, the copyright holders of Avisynth give you
24 // permission to link Avisynth with independent modules that communicate with
25 // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
26 // terms of these independent modules, and to copy and distribute the
27 // resulting combined work under terms of your choice, provided that
28 // every copy of the combined work is accompanied by a complete copy of
29 // the source code of Avisynth (the version of Avisynth used to produce the
30 // combined work), being distributed under the terms of the GNU General
31 // Public License plus this exception. An independent module is a module
32 // which is not derived from or based on Avisynth, such as 3rd-party filters,
33 // import and export plugins, or graphical user interfaces.
34
35 #include "color.h"
36
37 #include <math.h>
38 #include <float.h>
39 #if defined(AVS_BSD) || defined(AVS_MACOS)
40 #include <stdlib.h>
41 #else
42 #include <malloc.h>
43 #endif
44 #include <stdio.h>
45
46 #ifdef AVS_WINDOWS
47 #include <avs/win.h>
48 #else
49 #include <avs/posix.h>
50 #endif
51
52 #include <avs/minmax.h>
53 #include "../core/internal.h"
54 #include <algorithm>
55 #include <sstream> // stringstream
56 #include <iomanip> // setprecision
57 #include <string>
58 #include "../convert/convert_helper.h"
59
60 static void coloryuv_showyuv(BYTE* pY, BYTE* pU, BYTE* pV, int y_pitch, int u_pitch, int v_pitch, int framenumber, bool full_range, int bits_per_pixel)
61 {
62 int internal_bitdepth = bits_per_pixel == 8 ? 8 : 10;
63
64 const int luma_min = full_range ? 0 : (16 << (internal_bitdepth - 8));
65 const int luma_max = full_range ? (1 << internal_bitdepth) - 1 : (235 << (internal_bitdepth - 8));
66
67 const int chroma_center = 128 << (internal_bitdepth - 8);
68 const int chroma_span = full_range ? (1 << (internal_bitdepth - 1)) - 1 : (112 << (internal_bitdepth - 8)); // +-127/+-112
69 const int chroma_min = chroma_center - chroma_span; // +-112 (16-240) -> +-127 (1-255)
70 const int chroma_max = chroma_center + chroma_span;
71
72 const int luma_range = luma_max - luma_min + 1; // 256/220 ,1024/880
73 const int chroma_range = chroma_max - chroma_min + 1;
74
75 const int luma_size = chroma_range * 2; // YUV output is always 4:2:0. Horizontal subsampling 2.
76
77 int luma;
78 // Calculate luma cycle
79 // 0,1..255,254,..1 = 2x256-2
80 // 0,1..1023,1022,..1 = 2*1024-2
81 luma = framenumber % (luma_range * 2 - 2);
82 if (luma > luma_range - 1)
83 luma = (luma_range * 2 - 2) - luma;
84 luma += luma_min;
85
86 // Set luma value
87 if (bits_per_pixel == 8) {
88 for (int y = 0; y < luma_size; y++) {
89 memset(pY, luma, luma_size);
90 pY += y_pitch;
91 }
92 }
93 else if (bits_per_pixel <= 16) {
94 // display size (thus luma range) covers the same as at 10 bits.
95 if (full_range) {
96 // stretch
97 const float factor = (float)((1 << bits_per_pixel) - 1) / ((1 << internal_bitdepth) - 1);
98 const int luma_target = (int)(luma * factor + 0.5f);
99 for (int y = 0; y < luma_size; y++) {
100 std::fill_n((uint16_t*)pY, luma_size, luma_target);
101 pY += y_pitch;
102 }
103 }
104 else {
105 // shift
106 const int luma_target = luma << (bits_per_pixel - internal_bitdepth);
107 for (int y = 0; y < luma_size; y++) {
108 std::fill_n((uint16_t*)pY, luma_size, luma_target);
109 pY += y_pitch;
110 }
111 }
112 }
113 else {
114 // 32 bit float
115 const float factor = 1.0f / ((1 << internal_bitdepth) - 1);
116 const float luma_target = luma * factor;
117 for (int y = 0; y < luma_size; y++) {
118 std::fill_n((float*)pY, luma_size, luma_target);
119 pY += y_pitch;
120 }
121 }
122
123 // Set chroma
124 if (full_range) {
125 if (bits_per_pixel != 32) {
126 // 8-16 bit full
127 const int chroma_center_target = 128 << (bits_per_pixel - 8);
128 const int chroma_span_target = full_range ? (1 << (bits_per_pixel - 1)) - 1 : (112 << (bits_per_pixel - 8)); // +-127/+-112
129 const float factor = (float)chroma_span_target / chroma_span;
130 const float chroma_center_target_plus_round = chroma_center_target + 0.5f;
131
132 if (bits_per_pixel == 8) {
133 for (int y = 0; y < chroma_range; y++)
134 {
135 for (int x = 0; x < chroma_range; x++) {
136 int pixel_u = chroma_min + x;
137 pixel_u = (int)((pixel_u - chroma_center) * factor + chroma_center_target_plus_round);
138 pU[x] = pixel_u;
139 }
140 int pixel_v = chroma_min + y;
141 pixel_v = (int)((pixel_v - chroma_center) * factor + chroma_center_target_plus_round);
142 std::fill_n((uint8_t*)pV, chroma_range, pixel_v);
143
144 pU += u_pitch;
145 pV += v_pitch;
146 }
147 }
148 else if (bits_per_pixel <= 16) {
149 for (int y = 0; y < chroma_range; y++)
150 {
151 for (int x = 0; x < chroma_range; x++) {
152 int pixel_u = chroma_min + x;
153 pixel_u = (int)((pixel_u - chroma_center) * factor + chroma_center_target_plus_round);
154 reinterpret_cast<uint16_t*>(pU)[x] = pixel_u;
155 }
156 int pixel_v = chroma_min + y;
157 pixel_v = (int)((pixel_v - chroma_center) * factor + chroma_center_target_plus_round);
158 std::fill_n((uint16_t*)pV, chroma_range, pixel_v);
159
160 pU += u_pitch;
161 pV += v_pitch;
162 }
163 }
164 }
165 else {
166 // 32 bit float, full
167 const float chroma_span_target = 0.5f; // +-0.5/+-112
168 const float factor = chroma_span_target / chroma_span;
169
170 for (int y = 0; y < chroma_range; y++)
171 {
172 for (int x = 0; x < chroma_range; x++) {
173 const int pixel_u = chroma_min + x;
174 const float pixel_u_f = (pixel_u - chroma_center) * factor;
175 reinterpret_cast<float*>(pU)[x] = pixel_u_f;
176 }
177
178 const int pixel_v = chroma_min + y;
179 const float pixel_v_f = (pixel_v - chroma_center) * factor;
180 std::fill_n((float*)pV, chroma_range, pixel_v_f);
181
182 pU += u_pitch;
183 pV += v_pitch;
184 }
185 }
186 // full end
187 }
188 else {
189 if (bits_per_pixel == 8) {
190 // 8 bit limited range
191 for (int y = 0; y < chroma_range; y++)
192 {
193 for (int x = 0; x < chroma_range; x++)
194 pU[x] = chroma_min + x;
195 const int pixel_v = chroma_min + y;
196 std::fill_n((uint8_t*)pV, chroma_range, pixel_v);
197 pU += u_pitch;
198 pV += v_pitch;
199 }
200 }
201 else if (bits_per_pixel <= 16) {
202 // 16 bit limited range
203 const int bitdiff = (bits_per_pixel - internal_bitdepth);
204 for (int y = 0; y < chroma_range; y++)
205 {
206 for (int x = 0; x < chroma_range; x++) {
207 reinterpret_cast<uint16_t*>(pU)[x] = (chroma_min + x) << bitdiff;
208 }
209 const int pixel_v = (chroma_min + y) << bitdiff;
210 std::fill_n((uint16_t*)pV, chroma_range, pixel_v);
211 pU += u_pitch;
212 pV += v_pitch;
213 }
214 }
215 else {
216 // 32 bit float limited
217 const float factor = 1.0f / ((1 << internal_bitdepth) - 1);
218 for (int y = 0; y < chroma_range; y++)
219 {
220 for (int x = 0; x < chroma_range; x++) {
221 reinterpret_cast<float*>(pU)[x] = (float)(chroma_min + x - chroma_center) * factor;
222 }
223 const float pixel_v = (float)(chroma_min + y - chroma_center) * factor;
224 std::fill_n((float*)pV, chroma_range, pixel_v);
225 pU += u_pitch;
226 pV += v_pitch;
227 }
228 }
229 }
230 }
231
232 // luts are only for integer bits 8/10/12/14/16. float will be realtime
233 template<typename pixel_t>
234 7 static void coloryuv_create_lut(BYTE* lut8, const ColorYUVPlaneConfig* config, int bits_per_pixel, bool tweaklike_params)
235 {
236 7 pixel_t* lut = reinterpret_cast<pixel_t*>(lut8);
237
238 // scale is 256/1024/4096/16384/65536
239 // normalize to [0..1) working range
240 7 const double value_normalization_scale = (double)((int64_t)1 << bits_per_pixel);
241 // For gamma pre-post correction.
242 7 const double tv_range_lo_normalized = 16.0 / 256.0;
243
244 7 const int lookup_size = 1 << bits_per_pixel; // 256, 1024, 4096, 16384, 65536
245 7 const int source_max = (1 << bits_per_pixel) - 1;
246
4/8
void coloryuv_create_lut<unsigned char>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✓ Branch 2 → 3 taken 5 times.
✓ Branch 2 → 4 taken 2 times.
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 5 taken 3 times.
void coloryuv_create_lut<unsigned short>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
7 const bool chroma = config->plane == PLANAR_U || config->plane == PLANAR_V;
247 7 const bool fulls = config->range == COLORYUV_RANGE_PC_TV;
248 7 const bool fulld = config->range == COLORYUV_RANGE_TV_PC;
249 // when COLORYUV_RANGE_NONE both are the same false
250
251 //-----------------------
252 7 bits_conv_constants d;
253 // When calculating src_pixel, src and dst are of the same bit depth
254
2/4
void coloryuv_create_lut<unsigned char>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✓ Branch 6 → 7 taken 4 times.
✓ Branch 6 → 28 taken 3 times.
void coloryuv_create_lut<unsigned short>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 28 not taken.
7 get_bits_conv_constants(d, chroma, fulls, fulld, bits_per_pixel, bits_per_pixel);
255
256 7 auto dst_offset_plus_round = d.dst_offset + 0.5;
257 7 const int src_pixel_min = 0;
258 7 const int src_pixel_max = source_max;
259
260 // parameters are not scaled by bitdepth (legacy 8 bit behaviour)
261
1/4
void coloryuv_create_lut<unsigned char>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 58 → 59 not taken.
✓ Branch 58 → 60 taken 7 times.
void coloryuv_create_lut<unsigned short>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 58 → 59 not taken.
✗ Branch 58 → 60 not taken.
7 double gain = tweaklike_params ? config->gain : (config->gain / 256 + 1.0);
262
1/4
void coloryuv_create_lut<unsigned char>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 61 → 62 not taken.
✓ Branch 61 → 63 taken 7 times.
void coloryuv_create_lut<unsigned short>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 61 → 62 not taken.
✗ Branch 61 → 63 not taken.
7 double contrast = tweaklike_params ? config->contrast : (config->contrast / 256 + 1.0);
263
1/4
void coloryuv_create_lut<unsigned char>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 64 → 65 not taken.
✓ Branch 64 → 66 taken 7 times.
void coloryuv_create_lut<unsigned short>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 64 → 65 not taken.
✗ Branch 64 → 66 not taken.
7 double gamma = tweaklike_params ? config->gamma : (config->gamma / 256 + 1.0);
264 7 double offset = config->offset / 256;
265
266 // for correct Y gamma
267 7 double range_factor_tv_to_pc = 255.0 / 219.0; // 16-235 ==> 0..255
268 7 double range_factor_pc_to_tv = 219.0 / 255.0; // 0..255 ==> 16-235 (219)
269
270 // for coring
271 7 const int tv_range_lo_luma_chroma = (16 << (bits_per_pixel - 8));
272 7 const int tv_range_hi_luma = (235 << (bits_per_pixel - 8));
273 7 const int tv_range_hi_chroma = (240 << (bits_per_pixel - 8));
274
275 // We know that the input is TV range for sure: (coring=true and !PC->TV), levels="TV->PC" or (new!) levels="TV"
276
4/16
void coloryuv_create_lut<unsigned char>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 67 → 68 not taken.
✓ Branch 67 → 69 taken 7 times.
✗ Branch 68 → 69 not taken.
✗ Branch 68 → 71 not taken.
✓ Branch 69 → 70 taken 6 times.
✓ Branch 69 → 71 taken 1 time.
✗ Branch 70 → 71 not taken.
✓ Branch 70 → 72 taken 6 times.
void coloryuv_create_lut<unsigned short>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 67 → 68 not taken.
✗ Branch 67 → 69 not taken.
✗ Branch 68 → 69 not taken.
✗ Branch 68 → 71 not taken.
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 71 not taken.
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 72 not taken.
7 const bool source_is_limited = (config->clip_tv && config->range != COLORYUV_RANGE_PC_TV) || config->range == COLORYUV_RANGE_TV_PC || config->force_tv_range;
277
278
2/4
void coloryuv_create_lut<unsigned char>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✓ Branch 90 → 74 taken 1792 times.
✓ Branch 90 → 91 taken 7 times.
void coloryuv_create_lut<unsigned short>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 90 → 74 not taken.
✗ Branch 90 → 91 not taken.
1799 for (int i = 0; i < lookup_size; i++) {
279 1792 double value = double(i);
280 1792 value /= value_normalization_scale; // normalize to [0..1). For chroma this makes the center to 0.5.
281 1792 value *= gain; // Applying gain
282 // Applying contrast. For chroma, this sets saturation
283 1792 value = (value - 0.5) * contrast + 0.5; // integer chroma center is transformed to 0, apply contrast
284 // in Classic AVS: constract is applied on the original value and not on the already gained value
285 // value = (value * gain) + ((value - 0.5) * contrast + 0.5) - value + (bright - 1);
286 1792 value += offset; // Applying offset
287
288 // Applying gamma. Only on Y
289
1/4
void coloryuv_create_lut<unsigned char>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✓ Branch 74 → 75 taken 1792 times.
✗ Branch 74 → 80 not taken.
void coloryuv_create_lut<unsigned short>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 74 → 75 not taken.
✗ Branch 74 → 80 not taken.
1792 if (gamma != 0) {
290
2/4
void coloryuv_create_lut<unsigned char>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✓ Branch 75 → 76 taken 256 times.
✓ Branch 75 → 78 taken 1536 times.
void coloryuv_create_lut<unsigned short>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 75 → 76 not taken.
✗ Branch 75 → 78 not taken.
1792 if (source_is_limited) {
291 // avs+ 180301- use gamma on the proper 0.0 based value
292
2/4
void coloryuv_create_lut<unsigned char>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✓ Branch 76 → 77 taken 239 times.
✓ Branch 76 → 80 taken 17 times.
void coloryuv_create_lut<unsigned short>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 76 → 77 not taken.
✗ Branch 76 → 80 not taken.
256 if (value > tv_range_lo_normalized)
293 {
294 // tv->pc
295 239 value = (value - tv_range_lo_normalized) * range_factor_tv_to_pc; // (v-16)*range
296 239 value = pow(value, 1.0 / gamma);
297 // pc->tv
298 239 value = value * range_factor_pc_to_tv + tv_range_lo_normalized; // v*range - 16
299 }
300 }
301 else { // full (PC) range
302
2/4
void coloryuv_create_lut<unsigned char>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✓ Branch 78 → 79 taken 1502 times.
✓ Branch 78 → 80 taken 34 times.
void coloryuv_create_lut<unsigned short>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 80 not taken.
1536 if (value > 0)
303 1502 value = pow(value, 1.0 / gamma);
304 }
305 }
306
307 1792 value *= value_normalization_scale; // back from [0..1) range
308
309
2/4
void coloryuv_create_lut<unsigned char>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✓ Branch 80 → 81 taken 256 times.
✓ Branch 80 → 82 taken 1536 times.
void coloryuv_create_lut<unsigned short>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 82 not taken.
1792 if (fulls != fulld)
310 // Range conversion
311 256 value = (value - d.src_offset) * d.mul_factor + dst_offset_plus_round;
312 else
313 1536 value = value + 0.5; // rounder
314
315 // back to the integer world
316 1792 int iValue = clamp((int)value, src_pixel_min, src_pixel_max);
317
318
1/4
void coloryuv_create_lut<unsigned char>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 84 → 85 not taken.
✓ Branch 84 → 89 taken 1792 times.
void coloryuv_create_lut<unsigned short>(unsigned char*, ColorYUVPlaneConfig const*, int, bool):
✗ Branch 84 → 85 not taken.
✗ Branch 84 → 89 not taken.
1792 if (config->clip_tv) // set when coring
319 {
320 iValue = clamp(iValue, tv_range_lo_luma_chroma, config->plane == PLANAR_Y ? tv_range_hi_luma : tv_range_hi_chroma);
321 }
322
323 1792 lut[i] = iValue;
324 }
325 7 }
326
327 // works with <= 16 bits, but used only for float
328 static std::string coloryuv_create_lut_expr(const ColorYUVPlaneConfig* config, int bits_per_pixel, bool tweaklike_params)
329 {
330 const bool f32 = bits_per_pixel == 32;
331 const bool chroma = config->plane == PLANAR_U || config->plane == PLANAR_V;
332 // 32 bit float is already in [0..1] range but we have to make it similar to integer [0..1): needs /256 and not /255.
333 // Reason: match to the integer behaviour
334 // integer: normalize to [0..1) working range
335 const double value_normalization_scale = f32 ? (256.0 / 255.0) : (double)((int64_t)1 << bits_per_pixel);
336 // For gamma pre-post correction. we are in [0..1) working range
337 const double tv_range_lo_normalized = 16.0 / 256.0;
338
339 //const double source_max = f32 ? 1.0 : (double)((1 << bits_per_pixel) - 1);
340 const bool fulls = config->range == COLORYUV_RANGE_PC_TV;
341 const bool fulld = config->range == COLORYUV_RANGE_TV_PC;
342 // when COLORYUV_RANGE_NONE both are the same false
343
344 bits_conv_constants d;
345 // When calculating src_pixel, src and dst are of the same bit depth
346 get_bits_conv_constants(d, chroma, fulls, fulld, bits_per_pixel, bits_per_pixel);
347
348 auto dst_offset_no_round = d.dst_offset;
349 //const auto src_pixel_max = source_max;
350
351 // parameters are not scaled by bitdepth (legacy 8 bit behaviour)
352 double gain = tweaklike_params ? config->gain : (config->gain / 256 + 1.0);
353 double contrast = tweaklike_params ? config->contrast : (config->contrast / 256 + 1.0);
354 double gamma = tweaklike_params ? config->gamma : (config->gamma / 256 + 1.0);
355 double offset = config->offset / 256; // always in the 256 range
356
357 // for correct Y gamma
358 double range_factor_tv_to_pc = 255.0 / 219.0; // 16-235 ==> 0..255
359 double range_factor_pc_to_tv = 219.0 / 255.0; // 0..255 ==> 16-235 (219)
360
361 // We know that the input is TV range for sure: (coring=true and !PC->TV), levels="TV->PC" or (new!) levels="TV"
362 const bool source_is_limited = (config->clip_tv && config->range != COLORYUV_RANGE_PC_TV) || config->range == COLORYUV_RANGE_TV_PC || config->force_tv_range;
363
364 std::stringstream ss;
365
366 // value = double(i), we are using floats here
367 ss << "x";
368
369 // value = value / value_normalization_scale;
370 if (chroma && f32)
371 ss << " 255 * 256 / 0.5 + "; // from float chroma +/- to match with legacy integer behaviour
372 else
373 ss << " " << value_normalization_scale << " /";
374
375 if (gain != 1.0)
376 ss << " " << gain << " *"; // Applying gain // value *= gain;
377
378 // Applying contrast. For chroma, this sets saturation
379 // value = (value - 0.5) * contrast + 0.5;
380 // earlier we made measures that float chroma center is kept at 0.5
381 ss << " 0.5 - " << contrast << " * 0.5 +";
382
383 // value += offset; // Applying offset
384 ss << " " << offset << " +";
385
386 // Applying gamma. Only on Y
387 if (gamma != 0) {
388 if (source_is_limited) {
389 // avs+ 180301- use gamma on the proper 0.0 based value
390 // value = value > 16scaled ? (pow((value - 16scl)*range_tv_pc,(1/gamma))*range_pc_tv+16d : value
391 ss << " A@ " << tv_range_lo_normalized << " > " // condition: value > tv_range_lo_normalized
392 // case: true. tv->pc, power, pc->tv
393 << "A " << tv_range_lo_normalized << " - " << range_factor_tv_to_pc << " * " << (1.0 / gamma) << " pow " << range_factor_pc_to_tv << " * " << tv_range_lo_normalized << " + "
394 // case: false. Original value
395 << " A ? ";
396 }
397 else { // full (PC) range
398 //if (value > 0)
399 // value = pow(value, 1.0 / gamma);
400 // value = value > 0 ? pow(value,(1/gamma)) : value
401 ss << " A@ 0 > A " << (1.0 / gamma) << " pow A ? ";
402 }
403 }
404
405 if (chroma && f32)
406 ss << " 0.5 - 256 * 255 / ";
407 else
408 ss << " " << value_normalization_scale << " * "; // value *= value_normalization_scale; // back from [0..1) range
409
410 if (fulls != fulld) {
411 ss << d.src_offset << " - " << d.mul_factor << " * " << dst_offset_no_round << " + ";
412 // value = (value - d.src_offset) * d.mul_factor + dst_offset_no_round; // no rounder, Expr will round automatically before return
413 }
414 else {
415 // value = value + 0.5; // no rounder, Expr rounds
416 }
417
418 // clamp to the original valid bitdepth is done by Expr
419 // int iValue = clamp((int)value, src_pixel_min, src_pixel_max);
420 // ss << " " << src_pixel_min << " max " << src_pixel_max << " min ";
421
422 if (config->clip_tv) // set when coring
423 {
424 double tv_range_lo_luma = f32 ? (16.0 / 255) : ((int64_t)16 << (bits_per_pixel - 8));
425 double tv_range_hi_luma = f32 ? (235.0 / 255) : ((int64_t)235 << (bits_per_pixel - 8));
426 double tv_range_lo_chroma = f32 ? (-112.0 / 255.0) : ((int64_t)16 << (bits_per_pixel - 8)); // 112/255.0 consistent with get_bits_conv_constants()
427 double tv_range_hi_chroma = f32 ? (+112.0 / 255.0) : ((int64_t)240 << (bits_per_pixel - 8));
428 ss << (config->plane == PLANAR_Y ? tv_range_lo_luma : tv_range_lo_chroma) << " max ";
429 ss << (config->plane == PLANAR_Y ? tv_range_hi_luma : tv_range_hi_chroma) << " min ";
430 //iValue = clamp(iValue, tv_range_lo_luma, config->plane == PLANAR_Y ? tv_range_hi_luma : tv_range_hi_chroma);
431 }
432
433 std::string exprString = ss.str();
434 return exprString;
435
436 }
437
438 // for float, only loose_min and loose_max is counted
439 template<bool forFloat>
440 static void coloryuv_analyse_core(const int* freq, const int pixel_num, ColorYUVPlaneData* data, int bits_per_pixel_for_stat)
441 {
442 // 32 bit float reached here as split into ranges like a 16bit clip
443 int pixel_value_count = 1 << bits_per_pixel_for_stat; // size of freq table
444
445 const int pixel_256th = pixel_num / 256; // For loose max/min yes, still 1/256!
446
447 double avg = 0.0;
448 int real_min, real_max;
449
450 if (!forFloat) {
451 real_min = -1;
452 real_max = -1;
453 }
454 data->loose_max = -1;
455 data->loose_min = -1;
456
457 int px_min_c = 0, px_max_c = 0;
458
459 for (int i = 0; i < pixel_value_count; i++)
460 {
461 if (!forFloat) {
462 avg += freq[i] * double(i);
463
464 if (freq[i] > 0 && real_min == -1)
465 {
466 real_min = i;
467 }
468 }
469
470 if (data->loose_min == -1)
471 {
472 px_min_c += freq[i];
473
474 if (px_min_c > pixel_256th)
475 {
476 data->loose_min = i;
477 }
478 }
479
480 if (!forFloat) {
481 if (freq[pixel_value_count - 1 - i] > 0 && real_max == -1)
482 {
483 real_max = pixel_value_count - 1 - i;
484 }
485 }
486
487 if (data->loose_max == -1)
488 {
489 px_max_c += freq[pixel_value_count - 1 - i];
490
491 if (px_max_c > pixel_256th)
492 {
493 data->loose_max = pixel_value_count - 1 - i;
494 }
495 }
496 }
497
498 if (!forFloat) {
499 avg /= pixel_num;
500 data->average = avg;
501 data->real_min = (float)real_min;
502 data->real_max = (float)real_max;
503 }
504 }
505
506
507 static void coloryuv_analyse_planar(const BYTE* pSrc, int src_pitch, int width, int height, ColorYUVPlaneData* data, int bits_per_pixel, bool chroma)
508 {
509 // We can gather statistics from float, but for population count we have to
510 // split the range. We decide to split it into 2^16 ranges.
511 int bits_per_pixel_for_freq = bits_per_pixel <= 16 ? bits_per_pixel : 16;
512 int statistics_size = 1 << bits_per_pixel_for_freq; // float: 65536
513 int *freq = new int[statistics_size];
514 std::fill_n(freq, statistics_size, 0);
515
516 double sum = 0.0; // for float
517 float real_min;
518 float real_max;
519
520 if(bits_per_pixel==8) {
521 for (int y = 0; y < height; y++)
522 {
523 for (int x = 0; x < width; x++)
524 {
525 freq[pSrc[x]]++;
526 }
527
528 pSrc += src_pitch;
529 }
530 }
531 else if (bits_per_pixel >= 10 && bits_per_pixel <= 14) {
532 uint16_t mask = statistics_size - 1; // e.g. 0x3FF for 10 bit
533 for (int y = 0; y < height; y++)
534 {
535 for (int x = 0; x < width; x++)
536 {
537 freq[clamp(reinterpret_cast<const uint16_t *>(pSrc)[x],(uint16_t)0,mask)]++;
538 }
539
540 pSrc += src_pitch;
541 }
542 }
543 else if (bits_per_pixel == 16) {
544 // no clamp, faster
545 for (int y = 0; y < height; y++)
546 {
547 for (int x = 0; x < width; x++)
548 {
549 freq[reinterpret_cast<const uint16_t *>(pSrc)[x]]++;
550 }
551
552 pSrc += src_pitch;
553 }
554 } else if(bits_per_pixel==32) {
555 // 32 bits: we populate pixels only for loose_min and loose_max
556 // real_min and real_max, average (sum) is computed differently
557 real_min = reinterpret_cast<const float *>(pSrc)[0];
558 real_max = real_min;
559 if (chroma) {
560 const float shift = 32768.0f;
561 for (int y = 0; y < height; y++)
562 {
563 for (int x = 0; x < width; x++)
564 {
565 // -0.5..0.5 (0..1.0 when FLOAT_CHROMA_IS_HALF_CENTERED) to 0..65535
566 // see also: ConditionalFunctions MinMax
567 const float pixel = reinterpret_cast<const float *>(pSrc)[x];
568 freq[clamp((int)(65535.0f*pixel + shift + 0.5f), 0, 65535)]++;
569 // todo: SSE2
570 real_min = min(real_min, pixel);
571 real_max = max(real_max, pixel);
572 sum += pixel;
573 }
574 pSrc += src_pitch;
575 }
576 }
577 else {
578 for (int y = 0; y < height; y++)
579 {
580 for (int x = 0; x < width; x++)
581 {
582 // 0..1 -> 0..65535
583 const float pixel = reinterpret_cast<const float *>(pSrc)[x];
584 freq[clamp((int)(65535.0f*pixel + 0.5f), 0, 65535)]++;
585 // todo: SSE2
586 real_min = min(real_min, pixel);
587 real_max = max(real_max, pixel);
588 sum += pixel;
589 }
590
591 pSrc += src_pitch;
592 }
593 }
594 }
595
596
597 if (bits_per_pixel == 32) {
598 coloryuv_analyse_core<true>(freq, width*height, data, bits_per_pixel_for_freq);
599 data->average = sum / (height * width);
600 data->real_max = real_max;
601 data->real_min = real_min;
602 // loose min and max was shifted by half of 16bit range. We still keep here the range
603 if (chroma) {
604 data->loose_max = data->loose_max - 32768;
605 data->loose_min = data->loose_min - 32768;
606 }
607 // autogain treats it as a value of 16bit magnitude, show=true as well
608 //data->loose_min = data->loose_min / 65535.0f; not now.
609 //data->loose_max = data->loose_max / 65535.0f;
610 }
611 else {
612 coloryuv_analyse_core<false>(freq, width*height, data, bits_per_pixel_for_freq);
613 }
614
615 delete[] freq;
616 }
617
618 static void coloryuv_analyse_yuy2(const BYTE* pSrc, int src_pitch, int width, int height, ColorYUVPlaneData* dataY, ColorYUVPlaneData* dataU, ColorYUVPlaneData* dataV)
619 {
620 int freqY[256], freqU[256], freqV[256];
621 memset(freqY, 0, sizeof(freqY));
622 memset(freqU, 0, sizeof(freqU));
623 memset(freqV, 0, sizeof(freqV));
624
625 for (int y = 0; y < height; y++)
626 {
627 for (int x = 0; x < width*2; x+=4)
628 {
629 freqY[pSrc[x+0]]++;
630 freqU[pSrc[x+1]]++;
631 freqY[pSrc[x+2]]++;
632 freqV[pSrc[x+3]]++;
633 }
634
635 pSrc += src_pitch;
636 }
637
638 coloryuv_analyse_core<false>(freqY, width*height, dataY, 8);
639 coloryuv_analyse_core<false>(freqU, width*height/2, dataU, 8);
640 coloryuv_analyse_core<false>(freqV, width*height/2, dataV, 8);
641 }
642
643 static void coloryuv_autogain(const ColorYUVPlaneData* dY, const ColorYUVPlaneData* dU, const ColorYUVPlaneData* dV, ColorYUVPlaneConfig* cY, ColorYUVPlaneConfig* cU, ColorYUVPlaneConfig* cV,
644 int bits_per_pixel, bool tweaklike_params)
645 {
646 int bits_per_pixel_for_freq = bits_per_pixel <= 16 ? bits_per_pixel : 16; // for float: "loose" statistics like uint16_t
647 // always 16..235
648 int loose_max_limit = (235 + 1) << (bits_per_pixel_for_freq - 8);
649 int loose_min_limit = 16 << (bits_per_pixel_for_freq - 8);
650 int maxY = min(dY->loose_max, loose_max_limit);
651 int minY = max(dY->loose_min, loose_min_limit);
652
653 int range = maxY - minY;
654
655 if (range > 0) {
656 double scale = double(loose_max_limit - loose_min_limit) / range;
657 cY->offset = (loose_min_limit - scale * minY) / (1 << (bits_per_pixel_for_freq - 8)); // good for float also, 0..256 range
658 cY->gain = tweaklike_params ? scale : (256 * (scale - 1.0));
659 cY->changed = true;
660 }
661 }
662
663 static void coloryuv_autowhite(const ColorYUVPlaneData* dY, const ColorYUVPlaneData* dU, const ColorYUVPlaneData* dV, ColorYUVPlaneConfig* cY, ColorYUVPlaneConfig* cU, ColorYUVPlaneConfig* cV,
664 int bits_per_pixel)
665 {
666 if (bits_per_pixel == 32) {
667 #ifdef FLOAT_CHROMA_IS_HALF_CENTERED
668 double middle = 0.5;
669 #else
670 double middle = 0.0;
671 #endif
672 cU->offset = (middle - dU->average) * 256; // parameter is in 256 range
673 cV->offset = (middle - dV->average) * 256;
674 }
675 else {
676 double middle = (1 << (bits_per_pixel - 1)) - 1; // 128-1, 2048-1 ...
677 cU->offset = (middle - dU->average) / (1 << (bits_per_pixel - 8)); // parameter is in 256 range
678 cV->offset = (middle - dV->average) / (1 << (bits_per_pixel - 8));
679 }
680 cU->changed = true;
681 cV->changed = true;
682 }
683
684 // only for integer samples
685 7 static void coloryuv_apply_lut_planar(BYTE* pDst, const BYTE* pSrc, int dst_pitch, int src_pitch, int width, int height, const BYTE* lut, int bits_per_pixel)
686 {
687
1/2
✓ Branch 2 → 3 taken 7 times.
✗ Branch 2 → 9 not taken.
7 if(bits_per_pixel==8)
688 {
689
2/2
✓ Branch 8 → 4 taken 20 times.
✓ Branch 8 → 28 taken 7 times.
27 for (int y = 0; y < height; y++)
690 {
691
2/2
✓ Branch 6 → 5 taken 136 times.
✓ Branch 6 → 7 taken 20 times.
156 for (int x = 0; x < width; x++)
692 {
693 136 pDst[x] = lut[pSrc[x]];
694 }
695
696 20 pSrc += src_pitch;
697 20 pDst += dst_pitch;
698 }
699 }
700 else if (bits_per_pixel >= 10 && bits_per_pixel <= 14) {
701 uint16_t max_pixel_value = (1 << bits_per_pixel) - 1;
702 // protection needed for lut
703 for (int y = 0; y < height; y++)
704 {
705 for (int x = 0; x < width; x++)
706 {
707 uint16_t pixel = reinterpret_cast<const uint16_t *>(pSrc)[x];
708 pixel = pixel <= max_pixel_value ? pixel : max_pixel_value;
709 reinterpret_cast<uint16_t *>(pDst)[x] = reinterpret_cast<const uint16_t *>(lut)[pixel];
710 }
711
712 pSrc += src_pitch;
713 pDst += dst_pitch;
714 }
715 }
716 else if (bits_per_pixel == 16) {
717 // no protection, faster
718 for (int y = 0; y < height; y++)
719 {
720 for (int x = 0; x < width; x++)
721 {
722 reinterpret_cast<uint16_t *>(pDst)[x] = reinterpret_cast<const uint16_t *>(lut)[reinterpret_cast<const uint16_t *>(pSrc)[x]];
723 }
724
725 pSrc += src_pitch;
726 pDst += dst_pitch;
727 }
728 }
729 7 }
730
731 static void coloryuv_apply_lut_yuy2(BYTE* pDst, const BYTE* pSrc, int dst_pitch, int src_pitch, int width, int height, const BYTE* lutY, const BYTE* lutU, const BYTE* lutV)
732 {
733 for (int y = 0; y < height; y++)
734 {
735 for (int x = 0; x < width * 2; x += 4)
736 {
737 pDst[x+0] = lutY[pSrc[x + 0]];
738 pDst[x+1] = lutU[pSrc[x + 1]];
739 pDst[x+2] = lutY[pSrc[x + 2]];
740 pDst[x+3] = lutV[pSrc[x + 3]];
741 }
742
743 pSrc += src_pitch;
744 pDst += dst_pitch;
745 }
746 }
747
748 #define READ_CONDITIONAL(plane, var_name, internal_name, condVarSuffix) \
749 { \
750 std::string s = "coloryuv_" #var_name "_" #plane;\
751 s = s + condVarSuffix; \
752 const double t = env->GetVarDouble(s.c_str(), DBL_MIN); \
753 if (t != DBL_MIN) { \
754 c_##plane->internal_name = t; \
755 c_##plane->changed = true; \
756 } \
757 }
758
759 // extra: add extra at the end of variable names: different variables for multiple instances of coloryuv
760 static void coloryuv_read_conditional(IScriptEnvironment* env, ColorYUVPlaneConfig* c_y, ColorYUVPlaneConfig* c_u, ColorYUVPlaneConfig* c_v, const char *condVarSuffix)
761 {
762 READ_CONDITIONAL(y, gain, gain, condVarSuffix);
763 READ_CONDITIONAL(y, off, offset, condVarSuffix);
764 READ_CONDITIONAL(y, gamma, gamma, condVarSuffix);
765 READ_CONDITIONAL(y, cont, contrast, condVarSuffix);
766
767 READ_CONDITIONAL(u, gain, gain, condVarSuffix);
768 READ_CONDITIONAL(u, off, offset, condVarSuffix);
769 READ_CONDITIONAL(u, gamma, gamma, condVarSuffix);
770 READ_CONDITIONAL(u, cont, contrast, condVarSuffix);
771
772 READ_CONDITIONAL(v, gain, gain, condVarSuffix);
773 READ_CONDITIONAL(v, off, offset, condVarSuffix);
774 READ_CONDITIONAL(v, gamma, gamma, condVarSuffix);
775 READ_CONDITIONAL(v, cont, contrast, condVarSuffix);
776 }
777
778 #undef READ_CONDITIONAL
779
780 3 ColorYUV::ColorYUV(PClip child,
781 double gain_y, double offset_y, double gamma_y, double contrast_y,
782 double gain_u, double offset_u, double gamma_u, double contrast_u,
783 double gain_v, double offset_v, double gamma_v, double contrast_v,
784 const char* level, const char* opt,
785 bool showyuv, bool analyse, bool autowhite, bool autogain, bool conditional,
786 int bits, bool showyuv_fullrange,
787 bool tweaklike_params, // ColorYUV2: 0.0/0.5/1.0/2.0/3.0 instead of -256/-128/0/256/512
788 const char* condVarSuffix,
789 bool optForceUseExpr,
790 3 IScriptEnvironment* env)
791 : GenericVideoFilter(child),
792 3 colorbar_bits(showyuv ? bits : 0), colorbar_fullrange(showyuv_fullrange),
793 3 analyse(analyse), autowhite(autowhite), autogain(autogain), conditional(conditional),
794
3/6
✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 106 not taken.
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 104 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 3 times.
3 tweaklike_params(tweaklike_params), condVarSuffix(condVarSuffix), optForceUseExpr(optForceUseExpr)
795 {
796 3 luts[0] = luts[1] = luts[2] = nullptr;
797
798
6/10
✓ Branch 8 → 9 taken 3 times.
✗ Branch 8 → 109 not taken.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 13 taken 2 times.
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 109 not taken.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 1 time.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 3 times.
3 if (!vi.IsYUV() && !vi.IsYUVA())
799 env->ThrowError("ColorYUV: Only work with YUV colorspace.");
800
801 3 bool ColorRangeCanBeGuessed = false;
802
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 3 times.
3 if (gamma_y != 0) {
803 ColorRangeCanBeGuessed = true;
804 // when gamma is used then we must know the color range full/limited
805 // and the default is full_scale if gamma is not zero
806 }
807
808 3 configY.gain = gain_y;
809 3 configY.offset = offset_y;
810 3 configY.gamma = gamma_y;
811 3 configY.contrast = contrast_y;
812 3 configY.changed = false;
813 3 configY.clip_tv = false;
814 3 configY.force_tv_range = false;
815 3 configY.plane = PLANAR_Y;
816
817 3 configU.gain = gain_u;
818 3 configU.offset = offset_u;
819 3 configU.gamma = gamma_u;
820 3 configU.contrast = contrast_u;
821 3 configU.changed = false;
822 3 configU.clip_tv = false;
823 3 configU.force_tv_range = false; // n/a. in chroma. For gamma
824 3 configU.plane = PLANAR_U;
825
826 3 configV.gain = gain_v;
827 3 configV.offset = offset_v;
828 3 configV.gamma = gamma_v;
829 3 configV.contrast = contrast_v;
830 3 configV.changed = false;
831 3 configV.clip_tv = false;
832 3 configV.force_tv_range = false; // n/a. in chroma. For gamma
833 3 configV.plane = PLANAR_V;
834
835 // Range
836
2/2
✓ Branch 18 → 19 taken 1 time.
✓ Branch 18 → 20 taken 2 times.
3 if (lstrcmpi(level, "TV->PC") == 0)
837 {
838 1 ColorRangeCanBeGuessed = true; // will be full
839 1 configV.range = configU.range = configY.range = COLORYUV_RANGE_TV_PC;
840 }
841
1/2
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 2 times.
2 else if (lstrcmpi(level, "PC->TV") == 0)
842 {
843 ColorRangeCanBeGuessed = true;// will be limited
844 configV.range = configU.range = configY.range = COLORYUV_RANGE_PC_TV;
845 }
846
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 2 times.
2 else if (lstrcmpi(level, "PC->TV.Y") == 0)
847 { // ?
848 ColorRangeCanBeGuessed = true;// will be limited
849 configV.range = configU.range = COLORYUV_RANGE_NONE;
850 configY.range = COLORYUV_RANGE_PC_TV;
851 }
852
1/2
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 2 times.
2 else if (lstrcmpi(level, "TV") == 0)
853 {
854 // When no range conversion occurs only gamma correction
855 // By this parameter we know it will be limited, this info is used for gamma adjustment
856 ColorRangeCanBeGuessed = true;
857 configV.force_tv_range = configU.force_tv_range = configY.force_tv_range = true;
858 }
859
1/2
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 28 taken 2 times.
2 else if (lstrcmpi(level, "") != 0)
860 {
861 env->ThrowError("ColorYUV: invalid parameter : levels");
862 }
863 else {
864 2 configV.range = configU.range = configY.range = COLORYUV_RANGE_NONE;
865 }
866
867 // Option
868
1/2
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 3 times.
3 if (lstrcmpi(opt, "coring") == 0)
869 {
870 // note: this setting can conflict with e.g. TV->PC but we do not report an error
871 ColorRangeCanBeGuessed = true; // used to set _ColorRange=limited only if not conversion mode is specified
872 configY.clip_tv = true;
873 configU.clip_tv = true;
874 configV.clip_tv = true;
875 }
876
1/2
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 33 taken 3 times.
3 else if (lstrcmpi(opt, "") != 0)
877 {
878 env->ThrowError("ColorYUV: invalid parameter : opt");
879 }
880
881
1/2
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 59 taken 3 times.
3 if (showyuv) {
882 if (colorbar_bits != 8 && colorbar_bits != 10 && colorbar_bits != 12 && colorbar_bits != 14 && colorbar_bits != 16 && colorbar_bits != 32)
883 env->ThrowError("ColorYUV: bits parameter for showyuv must be 8, 10, 12, 14, 16 or 32");
884
885 switch (colorbar_bits) {
886 case 8: vi.pixel_type = VideoInfo::CS_YV12; break;
887 case 10: vi.pixel_type = VideoInfo::CS_YUV420P10; break;
888 case 12: vi.pixel_type = VideoInfo::CS_YUV420P12; break;
889 case 14: vi.pixel_type = VideoInfo::CS_YUV420P14; break;
890 case 16: vi.pixel_type = VideoInfo::CS_YUV420P16; break;
891 case 32: vi.pixel_type = VideoInfo::CS_YUV420PS; break;
892 }
893 // pre-avs+: coloryuv_showyuv is always called with full_range false
894 const int internal_bitdepth = colorbar_bits == 8 ? 8 : 10;
895 const int chroma_span = colorbar_fullrange ? (1 << (internal_bitdepth - 1)) - 1 : (112 << (internal_bitdepth - 8)); // +-127/+-112
896 const int chroma_range = 2 * chroma_span + 1; // 1..255 (+-127), 16..240 (+-112)
897 // size limited to either 8 or 10 bits, independenly of 12/14/16 or 32bit float bit-depth
898 vi.width = chroma_range << vi.GetPlaneWidthSubsampling(PLANAR_U);
899 vi.height = vi.width;
900 theColorRange = colorbar_fullrange ? ColorRange_Compat_e::AVS_COLORRANGE_FULL : ColorRange_Compat_e::AVS_COLORRANGE_LIMITED;
901 theMatrix = Matrix_e::AVS_MATRIX_BT470_BG; // all the same
902 theChromaLocation = ChromaLocation_e::AVS_CHROMA_CENTER; // default "mpeg1" for 4:2:0
903 return;
904 }
905
906 // !showyuv, real filter
907
908
1/2
✓ Branch 60 → 61 taken 3 times.
✗ Branch 60 → 109 not taken.
3 auto frame0 = child->GetFrame(0, env);
909
1/2
✓ Branch 61 → 62 taken 3 times.
✗ Branch 61 → 107 not taken.
3 const AVSMap* props = env->getFramePropsRO(frame0);
910
2/4
✓ Branch 68 → 69 taken 3 times.
✗ Branch 68 → 107 not taken.
✓ Branch 69 → 70 taken 3 times.
✗ Branch 69 → 107 not taken.
6 matrix_parse_merge_with_props_def(vi.IsRGB(), vi.IsRGB(), nullptr, props, theMatrix, theColorRange,
911
1/2
✓ Branch 67 → 68 taken 3 times.
✗ Branch 67 → 107 not taken.
3 theOutColorRange, // n/a
912 Matrix_e::AVS_MATRIX_UNSPECIFIED, // default matrix n/a
913
1/2
✗ Branch 62 → 63 not taken.
✓ Branch 62 → 64 taken 3 times.
3 configY.force_tv_range ?
914 ColorRange_Compat_e::AVS_COLORRANGE_LIMITED :
915
2/2
✓ Branch 64 → 65 taken 1 time.
✓ Branch 64 → 66 taken 2 times.
3 ColorRangeCanBeGuessed ? ColorRange_Compat_e::AVS_COLORRANGE_FULL : -1 /* n/a invalid */, env);
916 // although we read _ColorRange full/limited, nothing stops us to feed with full-range clip a "TV->PC" conversion
917 // Anyway: a frame property can set theColorRange from the default "FULL" to the actual one.
918
2/3
✗ Branch 70 → 71 not taken.
✓ Branch 70 → 72 taken 1 time.
✓ Branch 70 → 73 taken 2 times.
3 switch (configY.range) {
919 case COLORYUV_RANGE_PC_TV:
920 case COLORYUV_RANGE_PC_TVY:
921 theColorRange = ColorRange_Compat_e::AVS_COLORRANGE_LIMITED;
922 break;
923 1 case COLORYUV_RANGE_TV_PC:
924 1 theColorRange = ColorRange_Compat_e::AVS_COLORRANGE_FULL;
925 1 break;
926 2 default:
927
1/2
✗ Branch 73 → 74 not taken.
✓ Branch 73 → 75 taken 2 times.
2 if (configY.force_tv_range) // "TV" overrides default "PC". Info is needed for gamma correction
928 theColorRange = ColorRange_Compat_e::AVS_COLORRANGE_LIMITED;
929
1/2
✗ Branch 75 → 76 not taken.
✓ Branch 75 → 77 taken 2 times.
2 else if (configY.clip_tv) // coring is also sets this frame property
930 theColorRange = ColorRange_Compat_e::AVS_COLORRANGE_LIMITED;
931 else
932 2 theColorRange = theOutColorRange;
933 2 break;
934 // leave color range as is
935 }
936 // theMatrix and theColorRange will set frame properties in GetFrame
937
938 // prepare basic LUT
939
1/2
✓ Branch 79 → 80 taken 3 times.
✗ Branch 79 → 107 not taken.
3 int pixelsize = vi.ComponentSize();
940
1/2
✓ Branch 80 → 81 taken 3 times.
✗ Branch 80 → 107 not taken.
3 int bits_per_pixel = vi.BitsPerComponent();
941
942
1/4
✗ Branch 81 → 82 not taken.
✓ Branch 81 → 83 taken 3 times.
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 101 not taken.
3 if (pixelsize == 1 || pixelsize == 2) {
943 // no float lut. float will be realtime
944 3 int lut_size = pixelsize * (1 << bits_per_pixel); // 256*1 / 1024*2 .. 65536*2
945
1/2
✓ Branch 83 → 84 taken 3 times.
✗ Branch 83 → 107 not taken.
3 luts[0] = new BYTE[lut_size];
946
3/4
✓ Branch 84 → 85 taken 3 times.
✗ Branch 84 → 107 not taken.
✓ Branch 85 → 86 taken 2 times.
✓ Branch 85 → 89 taken 1 time.
3 if (!vi.IsY()) {
947
1/2
✓ Branch 86 → 87 taken 2 times.
✗ Branch 86 → 107 not taken.
2 luts[1] = new BYTE[lut_size];
948
1/2
✓ Branch 87 → 88 taken 2 times.
✗ Branch 87 → 107 not taken.
2 luts[2] = new BYTE[lut_size];
949 }
950
951
1/2
✓ Branch 89 → 90 taken 3 times.
✗ Branch 89 → 95 not taken.
3 if (pixelsize == 1) {
952 3 coloryuv_create_lut<uint8_t>(luts[0], &configY, bits_per_pixel, tweaklike_params);
953
3/4
✓ Branch 91 → 92 taken 3 times.
✗ Branch 91 → 107 not taken.
✓ Branch 92 → 93 taken 2 times.
✓ Branch 92 → 101 taken 1 time.
3 if (!vi.IsY())
954 {
955 2 coloryuv_create_lut<uint8_t>(luts[1], &configU, bits_per_pixel, tweaklike_params);
956 2 coloryuv_create_lut<uint8_t>(luts[2], &configV, bits_per_pixel, tweaklike_params);
957 }
958 }
959 else if (pixelsize == 2) { // pixelsize==2
960 coloryuv_create_lut<uint16_t>(luts[0], &configY, bits_per_pixel, tweaklike_params);
961 if (!vi.IsY())
962 {
963 coloryuv_create_lut<uint16_t>(luts[1], &configU, bits_per_pixel, tweaklike_params);
964 coloryuv_create_lut<uint16_t>(luts[2], &configV, bits_per_pixel, tweaklike_params);
965 }
966 }
967 }
968 3 }
969
970 3 ColorYUV::~ColorYUV() {
971
2/4
✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 5 not taken.
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 5 not taken.
3 if (luts[0]) delete[] luts[0];
972
3/4
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 8 taken 1 time.
✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 8 not taken.
3 if (luts[1]) delete[] luts[1];
973
3/4
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 11 taken 1 time.
✓ Branch 9 → 10 taken 2 times.
✗ Branch 9 → 11 not taken.
3 if (luts[2]) delete[] luts[2];
974 3 }
975
976
977 3 PVideoFrame __stdcall ColorYUV::GetFrame(int n, IScriptEnvironment* env)
978 {
979
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 23 taken 3 times.
3 if (colorbar_bits>0)
980 {
981 PVideoFrame dst = env->NewVideoFrame(vi);
982 // no frame property source. It's like a source filter
983
984 auto props = env->getFramePropsRW(dst);
985 update_Matrix_and_ColorRange(props, theMatrix, theColorRange, env);
986 update_ChromaLocation(props, theChromaLocation, env);
987
988 // pre AVS+: full_range is always false
989 // AVS+: showyuv_fullrange bool parameter
990 // AVS+: bits parameter
991 coloryuv_showyuv(dst->GetWritePtr(), dst->GetWritePtr(PLANAR_U), dst->GetWritePtr(PLANAR_V), dst->GetPitch(), dst->GetPitch(PLANAR_U), dst->GetPitch(PLANAR_V), n, colorbar_fullrange, colorbar_bits);
992 return dst;
993 }
994
995
1/2
✓ Branch 24 → 25 taken 3 times.
✗ Branch 24 → 409 not taken.
3 PVideoFrame src = child->GetFrame(n, env);
996
1/2
✓ Branch 25 → 26 taken 3 times.
✗ Branch 25 → 407 not taken.
3 PVideoFrame dst;
997
998
1/2
✓ Branch 26 → 27 taken 3 times.
✗ Branch 26 → 405 not taken.
3 int pixelsize = vi.ComponentSize();
999
1/2
✓ Branch 27 → 28 taken 3 times.
✗ Branch 27 → 405 not taken.
3 int bits_per_pixel = vi.BitsPerComponent();
1000
1001 ColorYUVPlaneConfig // Yes, we copy these struct
1002 3 cY = configY,
1003 3 cU = configU,
1004 3 cV = configV;
1005
1006 // for analysing data
1007 char text[512];
1008
1009
3/6
✓ Branch 28 → 29 taken 3 times.
✗ Branch 28 → 31 not taken.
✓ Branch 29 → 30 taken 3 times.
✗ Branch 29 → 31 not taken.
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 76 taken 3 times.
3 if (analyse || autowhite || autogain)
1010 {
1011 ColorYUVPlaneData dY, dU, dV;
1012
1013 if (vi.IsYUY2())
1014 {
1015 coloryuv_analyse_yuy2(src->GetReadPtr(), src->GetPitch(), vi.width, vi.height, &dY, &dU, &dV);
1016 }
1017 else
1018 {
1019 coloryuv_analyse_planar(src->GetReadPtr(), src->GetPitch(), vi.width, vi.height, &dY, bits_per_pixel, false); // false: not chroma
1020 if (!vi.IsY())
1021 {
1022 const int width = vi.width >> vi.GetPlaneWidthSubsampling(PLANAR_U);
1023 const int height = vi.height >> vi.GetPlaneHeightSubsampling(PLANAR_U);
1024
1025 coloryuv_analyse_planar(src->GetReadPtr(PLANAR_U), src->GetPitch(PLANAR_U), width, height, &dU, bits_per_pixel, true); // true: chroma
1026 coloryuv_analyse_planar(src->GetReadPtr(PLANAR_V), src->GetPitch(PLANAR_V), width, height, &dV, bits_per_pixel, true);
1027 }
1028 }
1029
1030 if (analyse)
1031 {
1032 if (!vi.IsY())
1033 {
1034 if (bits_per_pixel == 32)
1035 sprintf(text,
1036 " Frame: %-8u ( Luma Y / ChromaU / ChromaV )\n"
1037 " Average: ( %7.5f / %7.5f / %7.5f )\n"
1038 " Minimum: ( %7.5f / %7.5f / %7.5f )\n"
1039 " Maximum: ( %7.5f / %7.5f / %7.5f )\n"
1040 "Loose Minimum: ( %7.5f / %7.5f / %7.5f )\n"
1041 "Loose Maximum: ( %7.5f / %7.5f / %7.5f )\n",
1042 n,
1043 dY.average, dU.average, dV.average,
1044 dY.real_min, dU.real_min, dV.real_min,
1045 dY.real_max, dU.real_max, dV.real_max,
1046 (float)dY.loose_min / 65535.0f, (float)dU.loose_min / 65535.0f, (float)dV.loose_min / 65535.0f,
1047 (float)dY.loose_max / 65535.0f, (float)dU.loose_max / 65535.0f, (float)dV.loose_max / 65535.0f
1048 );
1049 else
1050 sprintf(text,
1051 " Frame: %-8u ( Luma Y / ChromaU / ChromaV )\n"
1052 " Average: ( %7.2f / %7.2f / %7.2f )\n"
1053 " Minimum: ( %5d / %5d / %5d )\n"
1054 " Maximum: ( %5d / %5d / %5d )\n"
1055 "Loose Minimum: ( %5d / %5d / %5d )\n"
1056 "Loose Maximum: ( %5d / %5d / %5d )\n",
1057 n,
1058 dY.average, dU.average, dV.average,
1059 (int)dY.real_min, (int)dU.real_min, (int)dV.real_min,
1060 (int)dY.real_max, (int)dU.real_max, (int)dV.real_max,
1061 dY.loose_min, dU.loose_min, dV.loose_min,
1062 dY.loose_max, dU.loose_max, dV.loose_max
1063 );
1064 }
1065 else
1066 {
1067 if (bits_per_pixel == 32)
1068 sprintf(text,
1069 " Frame: %-8u\n"
1070 " Average: %7.5f\n"
1071 " Minimum: %7.5f\n"
1072 " Maximum: %7.5f\n"
1073 "Loose Minimum: %7.5f\n"
1074 "Loose Maximum: %7.5f\n",
1075 n,
1076 dY.average,
1077 dY.real_min,
1078 dY.real_max,
1079 (float)dY.loose_min / 65535.0f,
1080 (float)dY.loose_max / 65535.0f
1081 );
1082 else
1083 sprintf(text,
1084 " Frame: %-8u\n"
1085 " Average: %7.2f\n"
1086 " Minimum: %5d\n"
1087 " Maximum: %5d\n"
1088 "Loose Minimum: %5d\n"
1089 "Loose Maximum: %5d\n",
1090 n,
1091 dY.average,
1092 (int)dY.real_min,
1093 (int)dY.real_max,
1094 dY.loose_min,
1095 dY.loose_max
1096 );
1097 }
1098 }
1099
1100 if (autowhite && !vi.IsY())
1101 {
1102 coloryuv_autowhite(&dY, &dU, &dV, &cY, &cU, &cV, bits_per_pixel);
1103 }
1104
1105 if (autogain)
1106 {
1107 coloryuv_autogain(&dY, &dU, &dV, &cY, &cU, &cV, bits_per_pixel, tweaklike_params);
1108 }
1109 }
1110
1111 // Read conditional variables
1112
1/2
✗ Branch 76 → 77 not taken.
✓ Branch 76 → 78 taken 3 times.
3 if(conditional)
1113 coloryuv_read_conditional(env, &cY, &cU, &cV, condVarSuffix);
1114
1115 // no float lut. float will be realtime
1116
2/6
✗ Branch 78 → 79 not taken.
✓ Branch 78 → 80 taken 3 times.
✗ Branch 79 → 80 not taken.
✗ Branch 79 → 171 not taken.
✓ Branch 80 → 81 taken 3 times.
✗ Branch 80 → 171 not taken.
3 if ((pixelsize == 1 || pixelsize == 2) && !optForceUseExpr) {
1117
1118 3 BYTE *luts_live[3] = { nullptr };
1119
1120 3 BYTE *lutY = luts[0];
1121 3 BYTE *lutU = luts[1];
1122 3 BYTE *lutV = luts[2];
1123
1124 // recalculate plane LUT only if changed
1125 3 int lut_size = pixelsize * (1 << bits_per_pixel); // 256*1 / 1024*2 .. 65536*2
1126
1/2
✗ Branch 81 → 82 not taken.
✓ Branch 81 → 87 taken 3 times.
3 if (cY.changed) {
1127 luts_live[0] = new BYTE[lut_size];
1128 lutY = luts_live[0];
1129 if (pixelsize == 1)
1130 coloryuv_create_lut<uint8_t>(lutY, &cY, bits_per_pixel, tweaklike_params);
1131 else if (pixelsize == 2)
1132 coloryuv_create_lut<uint16_t>(lutY, &cY, bits_per_pixel, tweaklike_params);
1133 }
1134
1135
3/4
✓ Branch 87 → 88 taken 3 times.
✗ Branch 87 → 299 not taken.
✓ Branch 88 → 89 taken 2 times.
✓ Branch 88 → 101 taken 1 time.
3 if (!vi.IsY())
1136 {
1137
1/2
✗ Branch 89 → 90 not taken.
✓ Branch 89 → 95 taken 2 times.
2 if (cU.changed) {
1138 luts_live[1] = new BYTE[lut_size];
1139 lutU = luts_live[1];
1140 if (pixelsize == 1)
1141 coloryuv_create_lut<uint8_t>(lutU, &cU, bits_per_pixel, tweaklike_params);
1142 else if (pixelsize == 2)
1143 coloryuv_create_lut<uint16_t>(lutU, &cU, bits_per_pixel, tweaklike_params);
1144 }
1145
1/2
✗ Branch 95 → 96 not taken.
✓ Branch 95 → 101 taken 2 times.
2 if (cV.changed) {
1146 luts_live[2] = new BYTE[lut_size];
1147 lutV = luts_live[2];
1148 if (pixelsize == 1)
1149 coloryuv_create_lut<uint8_t>(lutV, &cV, bits_per_pixel, tweaklike_params);
1150 else if (pixelsize == 2)
1151 coloryuv_create_lut<uint16_t>(lutV, &cV, bits_per_pixel, tweaklike_params);
1152 }
1153 }
1154
2/4
✓ Branch 101 → 102 taken 3 times.
✗ Branch 101 → 298 not taken.
✓ Branch 102 → 103 taken 3 times.
✗ Branch 102 → 296 not taken.
3 dst = env->NewVideoFrameP(vi, &src);
1155
1156
2/4
✓ Branch 104 → 105 taken 3 times.
✗ Branch 104 → 299 not taken.
✗ Branch 105 → 106 not taken.
✓ Branch 105 → 115 taken 3 times.
3 if (vi.IsYUY2())
1157 {
1158 coloryuv_apply_lut_yuy2(dst->GetWritePtr(), src->GetReadPtr(), dst->GetPitch(), src->GetPitch(), vi.width, vi.height, lutY, lutU, lutV);
1159 }
1160 else
1161 {
1162
4/8
✓ Branch 116 → 117 taken 3 times.
✗ Branch 116 → 299 not taken.
✓ Branch 118 → 119 taken 3 times.
✗ Branch 118 → 299 not taken.
✓ Branch 120 → 121 taken 3 times.
✗ Branch 120 → 299 not taken.
✓ Branch 122 → 123 taken 3 times.
✗ Branch 122 → 299 not taken.
3 coloryuv_apply_lut_planar(dst->GetWritePtr(), src->GetReadPtr(), dst->GetPitch(), src->GetPitch(), vi.width, vi.height, lutY, bits_per_pixel);
1163
3/4
✓ Branch 124 → 125 taken 3 times.
✗ Branch 124 → 299 not taken.
✓ Branch 125 → 126 taken 2 times.
✓ Branch 125 → 146 taken 1 time.
3 if (!vi.IsY())
1164 {
1165
1/2
✓ Branch 126 → 127 taken 2 times.
✗ Branch 126 → 299 not taken.
2 const int width = vi.width >> vi.GetPlaneWidthSubsampling(PLANAR_U);
1166
1/2
✓ Branch 127 → 128 taken 2 times.
✗ Branch 127 → 299 not taken.
2 const int height = vi.height >> vi.GetPlaneHeightSubsampling(PLANAR_U);
1167
1168
4/8
✓ Branch 129 → 130 taken 2 times.
✗ Branch 129 → 299 not taken.
✓ Branch 131 → 132 taken 2 times.
✗ Branch 131 → 299 not taken.
✓ Branch 133 → 134 taken 2 times.
✗ Branch 133 → 299 not taken.
✓ Branch 135 → 136 taken 2 times.
✗ Branch 135 → 299 not taken.
2 coloryuv_apply_lut_planar(dst->GetWritePtr(PLANAR_U), src->GetReadPtr(PLANAR_U), dst->GetPitch(PLANAR_U), src->GetPitch(PLANAR_U), width, height, lutU, bits_per_pixel);
1169
4/8
✓ Branch 138 → 139 taken 2 times.
✗ Branch 138 → 299 not taken.
✓ Branch 140 → 141 taken 2 times.
✗ Branch 140 → 299 not taken.
✓ Branch 142 → 143 taken 2 times.
✗ Branch 142 → 299 not taken.
✓ Branch 144 → 145 taken 2 times.
✗ Branch 144 → 299 not taken.
2 coloryuv_apply_lut_planar(dst->GetWritePtr(PLANAR_V), src->GetReadPtr(PLANAR_V), dst->GetPitch(PLANAR_V), src->GetPitch(PLANAR_V), width, height, lutV, bits_per_pixel);
1170 }
1171
3/4
✓ Branch 146 → 147 taken 3 times.
✗ Branch 146 → 299 not taken.
✓ Branch 147 → 148 taken 1 time.
✓ Branch 147 → 161 taken 2 times.
3 if (vi.IsYUVA()) {
1172
7/14
✓ Branch 149 → 150 taken 1 time.
✗ Branch 149 → 299 not taken.
✓ Branch 151 → 152 taken 1 time.
✗ Branch 151 → 299 not taken.
✓ Branch 153 → 154 taken 1 time.
✗ Branch 153 → 299 not taken.
✓ Branch 155 → 156 taken 1 time.
✗ Branch 155 → 299 not taken.
✓ Branch 157 → 158 taken 1 time.
✗ Branch 157 → 299 not taken.
✓ Branch 159 → 160 taken 1 time.
✗ Branch 159 → 299 not taken.
✓ Branch 160 → 161 taken 1 time.
✗ Branch 160 → 299 not taken.
1 env->BitBlt(dst->GetWritePtr(PLANAR_A), dst->GetPitch(PLANAR_A), src->GetReadPtr(PLANAR_A), src->GetPitch(PLANAR_A), src->GetRowSize(PLANAR_A), src->GetHeight(PLANAR_A));
1173 }
1174 }
1175
1176
1/4
✗ Branch 161 → 162 not taken.
✓ Branch 161 → 164 taken 3 times.
✗ Branch 162 → 163 not taken.
✗ Branch 162 → 164 not taken.
3 if (luts_live[0]) delete[] luts_live[0];
1177
1/4
✗ Branch 164 → 165 not taken.
✓ Branch 164 → 167 taken 3 times.
✗ Branch 165 → 166 not taken.
✗ Branch 165 → 167 not taken.
3 if (luts_live[1]) delete[] luts_live[1];
1178
1/4
✗ Branch 167 → 168 not taken.
✓ Branch 167 → 170 taken 3 times.
✗ Branch 168 → 169 not taken.
✗ Branch 168 → 170 not taken.
3 if (luts_live[2]) delete[] luts_live[2];
1179 3 } // lut create and use
1180 else {
1181 // 32 bit float: expr
1182 std::string exprY = coloryuv_create_lut_expr(&cY, bits_per_pixel, tweaklike_params);
1183 std::string exprU = !vi.IsY() ? coloryuv_create_lut_expr(&cU, bits_per_pixel, tweaklike_params) : "";
1184 std::string exprV = !vi.IsY() ? coloryuv_create_lut_expr(&cV, bits_per_pixel, tweaklike_params) : "";
1185 std::string exprA = ""; // copy
1186 // Invoke Expr
1187 AVSValue child2;
1188 if (vi.IsY()) {
1189 AVSValue new_args[2] = { child, exprY.c_str() };
1190 child2 = env->Invoke("Expr", AVSValue(new_args, 2)).AsClip();
1191 }
1192 else if(vi.IsYUV()) {
1193 AVSValue new_args[4] = { child, exprY.c_str(), exprU.c_str(), exprV.c_str() };
1194 child2 = env->Invoke("Expr", AVSValue(new_args, 4)).AsClip();
1195 }
1196 else if (vi.IsYUVA()) {
1197 AVSValue new_args[5] = { child, exprY.c_str(), exprU.c_str(), exprV.c_str(), exprA.c_str() };
1198 child2 = env->Invoke("Expr", AVSValue(new_args, 5)).AsClip();
1199 }
1200 dst = child2.AsClip()->GetFrame(n, env);
1201 }
1202
1203
1/2
✗ Branch 280 → 281 not taken.
✓ Branch 280 → 282 taken 3 times.
3 if (analyse)
1204 {
1205 env->ApplyMessage(&dst, vi, text, vi.width / 4, 0xa0a0a0, 0, 0);
1206 }
1207
1208 // when there was no such property from constructor and it could not be guessed then we do not put one
1209
3/4
✓ Branch 282 → 283 taken 2 times.
✓ Branch 282 → 284 taken 1 time.
✓ Branch 283 → 284 taken 2 times.
✗ Branch 283 → 286 not taken.
3 if (theColorRange == ColorRange_Compat_e::AVS_COLORRANGE_FULL || theColorRange == ColorRange_Compat_e::AVS_COLORRANGE_LIMITED) {
1210
1/2
✓ Branch 284 → 285 taken 3 times.
✗ Branch 284 → 405 not taken.
3 auto props = env->getFramePropsRW(dst);
1211
1/2
✓ Branch 285 → 286 taken 3 times.
✗ Branch 285 → 405 not taken.
3 update_ColorRange(props, theColorRange, env);
1212 }
1213
1214
1/2
✓ Branch 286 → 287 taken 3 times.
✗ Branch 286 → 405 not taken.
3 return dst;
1215 3 }
1216
1217 AVSValue __cdecl ColorYUV::Create(AVSValue args, void* , IScriptEnvironment* env)
1218 {
1219 const bool tweaklike_params = args[23].AsBool(false); // f2c = true: for tweak-like parameter interpretation
1220 const float def = tweaklike_params ? 1.0f : 0.0f;
1221 return new ColorYUV(args[0].AsClip(),
1222 args[1].AsFloat(def), // gain_y
1223 args[2].AsFloat(0.0f), // off_y bright
1224 args[3].AsFloat(def), // gamma_y
1225 args[4].AsFloat(def), // cont_y
1226 args[5].AsFloat(def), // gain_u
1227 args[6].AsFloat(0.0f), // off_u bright
1228 args[7].AsFloat(def), // gamma_u
1229 args[8].AsFloat(def), // cont_u
1230 args[9].AsFloat(def), // gain_v
1231 args[10].AsFloat(0.0f), // off_v
1232 args[11].AsFloat(def), // gamma_v
1233 args[12].AsFloat(def), // cont_v
1234 args[13].AsString(""), // levels = "", "TV->PC", "PC->TV"
1235 args[14].AsString(""), // opt = "", "coring"
1236 // args[15].AsString(""), // matrix = "", "rec.709"
1237 args[16].AsBool(false), // colorbars
1238 args[17].AsBool(false), // analyze
1239 args[18].AsBool(false), // autowhite
1240 args[19].AsBool(false), // autogain
1241 args[20].AsBool(false), // conditional
1242 args[21].AsInt(8), // bits avs+
1243 args[22].AsBool(false), // showyuv_fullrange avs+
1244 tweaklike_params, // for gain, gamma, cont: 0.0/0.5/1.0/2.0/3.0 instead of -256/-128/0/256/512
1245 args[24].AsString(""), // condvarsuffix avs+
1246 args[25].AsBool(false), // optForceUseExpr debug parameter
1247 env);
1248 }
1249
1250 extern const AVSFunction Color_filters[] = {
1251 { "ColorYUV", BUILTIN_FUNC_PREFIX,
1252 "c[gain_y]f[off_y]f[gamma_y]f[cont_y]f" \
1253 "[gain_u]f[off_u]f[gamma_u]f[cont_u]f" \
1254 "[gain_v]f[off_v]f[gamma_v]f[cont_v]f" \
1255 "[levels]s[opt]s[matrix]s[showyuv]b" \
1256 "[analyze]b[autowhite]b[autogain]b[conditional]b" \
1257 "[bits]i[showyuv_fullrange]b[f2c]b[condvarsuffix]s[optForceUseExpr]b", // avs+ 20180226- f2c-like parameters
1258 ColorYUV::Create},
1259 { 0 }
1260 };
1261
1262