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/8void 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/4void 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/4void 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/4void 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/4void 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/16void 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/4void 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/4void 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/4void 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/4void 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/4void 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/4void 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/4void 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 |