convert/convert_matrix.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Avisynth v2.5. Copyright 2002-2009 Ben Rudiak-Gould et al. | ||
| 2 | // http://avisynth.nl | ||
| 3 | |||
| 4 | // This program is free software; you can redistribute it and/or modify | ||
| 5 | // it under the terms of the GNU General Public License as published by | ||
| 6 | // the Free Software Foundation; either version 2 of the License, or | ||
| 7 | // (at your option) any later version. | ||
| 8 | // | ||
| 9 | // This program is distributed in the hope that it will be useful, | ||
| 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | // GNU General Public License for more details. | ||
| 13 | // | ||
| 14 | // You should have received a copy of the GNU General Public License | ||
| 15 | // along with this program; if not, write to the Free Software | ||
| 16 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit | ||
| 17 | // http://www.gnu.org/copyleft/gpl.html . | ||
| 18 | // | ||
| 19 | // Linking Avisynth statically or dynamically with other modules is making a | ||
| 20 | // combined work based on Avisynth. Thus, the terms and conditions of the GNU | ||
| 21 | // General Public License cover the whole combination. | ||
| 22 | // | ||
| 23 | // As a special exception, the copyright holders of Avisynth give you | ||
| 24 | // permission to link Avisynth with independent modules that communicate with | ||
| 25 | // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license | ||
| 26 | // terms of these independent modules, and to copy and distribute the | ||
| 27 | // resulting combined work under terms of your choice, provided that | ||
| 28 | // every copy of the combined work is accompanied by a complete copy of | ||
| 29 | // the source code of Avisynth (the version of Avisynth used to produce the | ||
| 30 | // combined work), being distributed under the terms of the GNU General | ||
| 31 | // Public License plus this exception. An independent module is a module | ||
| 32 | // which is not derived from or based on Avisynth, such as 3rd-party filters, | ||
| 33 | // import and export plugins, or graphical user interfaces. | ||
| 34 | |||
| 35 | |||
| 36 | #include "convert_matrix.h" | ||
| 37 | #include "convert_helper.h" | ||
| 38 | #include <avisynth.h> | ||
| 39 | #ifdef AVS_WINDOWS | ||
| 40 | #include <avs/win.h> | ||
| 41 | #else | ||
| 42 | #include <avs/posix.h> | ||
| 43 | #endif | ||
| 44 | #include <cmath> | ||
| 45 | |||
| 46 | /** | ||
| 47 | * SIMD scaling logic for PMADDWD (16-bit signed multipliers, 32-bit accumulators). | ||
| 48 | * RGB->YUV uses 15-bit scale as all coeffs are < 1.0 (max ~0.678, BT.2020 G weight), | ||
| 49 | * fully utilizing 16-bit coefficient precision without overflow. | ||
| 50 | * YUV->RGB requires 13-bit scale to accommodate chroma expansion coeffs up to ~1.881 | ||
| 51 | * (BT.2020 Cb->B), keeping scaled coefficients within int16 range. | ||
| 52 | * Fused YUV->YUV (e.g., 601->2020) needs 14-bit scale; diagonal gain slightly > 1.0 | ||
| 53 | * (~1.03 max) rules out 15-bit, but coeffs are well within 13-bit headroom. | ||
| 54 | * At 16-bit depth, errors partially average out during 32-bit accumulation before rounding. | ||
| 55 | * Avoid unifying all paths to 13-bit: RGB->YUV would degrade from ~±1 to ~±12 LSB worst-case. | ||
| 56 | * | ||
| 57 | * | Conversion | Scale | Max Coeff | LSB Error (16-bit) | Worst-Case Matrix | | ||
| 58 | * |-------------|--------|-----------|--------------------|---------------------| | ||
| 59 | * | RGB -> YUV | 15-bit | ~0.678 | ~±1 (near-exact) | BT.2020 (G weight) | | ||
| 60 | * | YUV -> RGB | 13-bit | ~1.881 | ~±8 (practical) | BT.2020 (Cb -> B) | | ||
| 61 | * | YUV -> YUV | 14-bit | ~1.030 | ~±2 (low noise) | 601 <-> 2020 fused | | ||
| 62 | * | ||
| 63 | * matrix="RGB" (IDENTITY) exception: If Kr=Kb=0 (Identity), coeffs reach 1.0. (1.0 << 15) = 32768, | ||
| 64 | * which overflows int16 (-32768 to 32767). Caller will check it and may diable int16 based SIMD optimization paths. | ||
| 65 | */ | ||
| 66 | |||
| 67 | 215 | static void BuildMatrix_Rgb2Yuv_core(double Kr, double Kb, int int_arith_shift, bool full_scale_s, bool full_scale_d, int bits_per_pixel, ConversionMatrix& matrix) | |
| 68 | { | ||
| 69 | 215 | bits_conv_constants luma, chroma; | |
| 70 | 215 | bits_conv_constants luma_to_32bit; | |
| 71 | |||
| 72 | // helpers for post-matrix conversion to 32-bit float (for high bit depth sources or targets, e.g. 16-bit to 32-bit float) | ||
| 73 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 24 taken 215 times.
|
215 | get_bits_conv_constants(luma_to_32bit, false, full_scale_s, full_scale_d, bits_per_pixel, 32); |
| 74 | 215 | matrix.target_span_f_32 = luma_to_32bit.dst_span; | |
| 75 | 215 | matrix.offset_out_f_32 = luma_to_32bit.dst_offset; | |
| 76 | |||
| 77 | // RGB is source, YUV is destination | ||
| 78 | // For RGB source / Y destination (both luma-like): | ||
| 79 |
1/2✗ Branch 54 → 55 not taken.
✓ Branch 54 → 76 taken 215 times.
|
215 | get_bits_conv_constants(luma, false, full_scale_s, full_scale_d, bits_per_pixel, bits_per_pixel); |
| 80 | // For UV destination (chroma behavior): | ||
| 81 | // Note: we only need dst_span for UV, so we use full_scale_d for both params | ||
| 82 |
1/2✓ Branch 106 → 107 taken 215 times.
✗ Branch 106 → 128 not taken.
|
215 | get_bits_conv_constants(chroma, true, full_scale_d, full_scale_d, bits_per_pixel, bits_per_pixel); |
| 83 | |||
| 84 | 215 | double Srgb_f = luma.src_span; // RGB input range | |
| 85 | 215 | double Sy_f = luma.dst_span; // Y output range | |
| 86 | 215 | double Suv_f = chroma.dst_span; // UV output range | |
| 87 | 215 | double Orgb_f = luma.src_offset; // RGB input offset | |
| 88 | 215 | double Oy_f = luma.dst_offset; // Y output offset | |
| 89 | |||
| 90 | // Derive integer versions (for <= 16 bit paths) | ||
| 91 | 215 | int Orgb = (int)Orgb_f; | |
| 92 | 215 | int Oy = (int)Oy_f; | |
| 93 | |||
| 94 | /* | ||
| 95 | Kr = {0.299, 0.2126} | ||
| 96 | Kb = {0.114, 0.0722} | ||
| 97 | Kg = 1 - Kr - Kb // {0.587, 0.7152} | ||
| 98 | Srgb = 255 | ||
| 99 | Sy = {219, 255} // { 235-16, 255-0 } | ||
| 100 | Suv = {112, 127} // { (240-16)/2, (255-0)/2 } | ||
| 101 | Oy = {16, 0} | ||
| 102 | Ouv = 128 | ||
| 103 | R = r/Srgb // 0..1 | ||
| 104 | G = g/Srgb | ||
| 105 | B = b/Srgb | ||
| 106 | Y = Kr*R + Kg*G + Kb*B // 0..1 | ||
| 107 | U = B - (Kr*R + Kg*G)/(1-Kb) //-1..1 | ||
| 108 | V = R - (Kg*G + Kb*B)/(1-Kr) | ||
| 109 | y = Y*Sy + Oy // 16..235, 0..255 | ||
| 110 | u = U*Suv + Ouv // 16..240, 1..255 | ||
| 111 | v = V*Suv + Ouv | ||
| 112 | */ | ||
| 113 | |||
| 114 | 215 | const int mulfac_int = 1 << int_arith_shift; | |
| 115 | 215 | const double mulfac = double(mulfac_int); | |
| 116 | 215 | const double Kg = 1. - Kr - Kb; | |
| 117 | |||
| 118 | // Symmetric rounding for both positive and negative coefficients | ||
| 119 | 1746 | auto round_coeff = [](double v) { | |
| 120 |
2/2✓ Branch 2 → 3 taken 974 times.
✓ Branch 2 → 4 taken 772 times.
|
1746 | return (int)(v >= 0 ? (v + 0.5) : (v - 0.5)); |
| 121 | }; | ||
| 122 | |||
| 123 | // Calculate double-precision coefficients | ||
| 124 | 215 | double y_b_f = Sy_f * Kb / Srgb_f; | |
| 125 | 215 | double y_g_f = Sy_f * Kg / Srgb_f; | |
| 126 | 215 | double y_r_f = Sy_f * Kr / Srgb_f; | |
| 127 | |||
| 128 | 215 | double u_b_f = Suv_f / Srgb_f; | |
| 129 | 215 | double u_g_f = Suv_f * Kg / (Kb - 1) / Srgb_f; | |
| 130 | 215 | double u_r_f = Suv_f * Kr / (Kb - 1) / Srgb_f; | |
| 131 | |||
| 132 | 215 | double v_b_f = Suv_f * Kb / (Kr - 1) / Srgb_f; | |
| 133 | 215 | double v_g_f = Suv_f * Kg / (Kr - 1) / Srgb_f; | |
| 134 | 215 | double v_r_f = Suv_f / Srgb_f; | |
| 135 | |||
| 136 | 215 | double offset_y_f = Oy_f; | |
| 137 | 215 | double offset_rgb_f = -Orgb_f; // Negative because addition is used | |
| 138 | |||
| 139 | // Store float versions | ||
| 140 | 215 | matrix.y_b_f = (float)y_b_f; | |
| 141 | 215 | matrix.y_g_f = (float)y_g_f; | |
| 142 | 215 | matrix.y_r_f = (float)y_r_f; | |
| 143 | 215 | matrix.u_b_f = (float)u_b_f; | |
| 144 | 215 | matrix.u_g_f = (float)u_g_f; | |
| 145 | 215 | matrix.u_r_f = (float)u_r_f; | |
| 146 | 215 | matrix.v_b_f = (float)v_b_f; | |
| 147 | 215 | matrix.v_g_f = (float)v_g_f; | |
| 148 | 215 | matrix.v_r_f = (float)v_r_f; | |
| 149 | 215 | matrix.offset_y_f = (float)offset_y_f; | |
| 150 | 215 | matrix.offset_rgb_f = (float)offset_rgb_f; | |
| 151 | |||
| 152 |
2/2✓ Branch 158 → 159 taken 194 times.
✓ Branch 158 → 176 taken 21 times.
|
215 | if (bits_per_pixel <= 16) { |
| 153 | // Derive integer versions from doubles with proper rounding | ||
| 154 | 194 | matrix.y_b = round_coeff(mulfac * y_b_f); | |
| 155 | 194 | matrix.y_g = round_coeff(mulfac * y_g_f); | |
| 156 | 194 | matrix.y_r = round_coeff(mulfac * y_r_f); | |
| 157 | |||
| 158 | 194 | matrix.u_b = round_coeff(mulfac * u_b_f); | |
| 159 | 194 | matrix.u_g = round_coeff(mulfac * u_g_f); | |
| 160 | 194 | matrix.u_r = round_coeff(mulfac * u_r_f); | |
| 161 | |||
| 162 | 194 | matrix.v_b = round_coeff(mulfac * v_b_f); | |
| 163 | 194 | matrix.v_g = round_coeff(mulfac * v_g_f); | |
| 164 | 194 | matrix.v_r = round_coeff(mulfac * v_r_f); | |
| 165 | |||
| 166 | 194 | matrix.offset_y = Oy; | |
| 167 | 194 | matrix.offset_rgb = -Orgb; // negative because addition is used | |
| 168 | |||
| 169 | // Luma gain check: ensure Y captures 100% of RGB energy | ||
| 170 | // Only applies when destination is full-range (no offset) | ||
| 171 | // and the source RGB is similarly full_range | ||
| 172 |
4/4✓ Branch 168 → 169 taken 102 times.
✓ Branch 168 → 172 taken 92 times.
✓ Branch 169 → 170 taken 63 times.
✓ Branch 169 → 172 taken 39 times.
|
194 | if (full_scale_s && full_scale_d) { |
| 173 | 63 | int y_sum = matrix.y_b + matrix.y_g + matrix.y_r; | |
| 174 |
2/2✓ Branch 170 → 171 taken 9 times.
✓ Branch 170 → 172 taken 54 times.
|
63 | if (y_sum != mulfac_int) { |
| 175 | 9 | matrix.y_g += (mulfac_int - y_sum); | |
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | // U neutrality check: ensure R=G=B results in U = 0 (before offset) | ||
| 180 | 194 | int u_sum = matrix.u_b + matrix.u_g + matrix.u_r; | |
| 181 |
2/2✓ Branch 172 → 173 taken 9 times.
✓ Branch 172 → 174 taken 185 times.
|
194 | if (u_sum != 0) { |
| 182 | 9 | matrix.u_g -= u_sum; | |
| 183 | } | ||
| 184 | |||
| 185 | // V neutrality check: ensure R=G=B results in V = 0 (before offset) | ||
| 186 | 194 | int v_sum = matrix.v_b + matrix.v_g + matrix.v_r; | |
| 187 |
2/2✓ Branch 174 → 175 taken 43 times.
✓ Branch 174 → 176 taken 151 times.
|
194 | if (v_sum != 0) { |
| 188 | 43 | matrix.v_g -= v_sum; | |
| 189 | } | ||
| 190 | |||
| 191 | } | ||
| 192 | |||
| 193 | // in: rgb. out: yuv | ||
| 194 | 215 | matrix.offset_in = matrix.offset_rgb; | |
| 195 | 215 | matrix.offset_in_f = matrix.offset_rgb_f; | |
| 196 | 215 | matrix.offset_out = matrix.offset_y; | |
| 197 | 215 | matrix.offset_out_f = matrix.offset_y_f; | |
| 198 | 215 | } | |
| 199 | |||
| 200 | /* | ||
| 201 | * WARNING: int_arith_shift MUST NOT exceed 13 for YUV -> RGB expansion. | ||
| 202 | * Example: BT.709 Limited -> Full Range | ||
| 203 | * The Blue expansion factor (u_b_f) is ~2.112. | ||
| 204 | * - At 14-bit shift: 2.112 * 16384 = 34603 (OVERFLOWS int16_t) | ||
| 205 | * - At 13-bit shift: 2.112 * 8192 = 17302 (SAFE) | ||
| 206 | * Use 13-bit shift to ensure coefficients fit in int16 for SIMD paths. | ||
| 207 | * Additionally, summing up to 3 components (Y, U, V) plus rounding constant must | ||
| 208 | * not overflow int32 accumulators in SIMD. (another 2 bits headroom needed) | ||
| 209 | */ | ||
| 210 | 115 | static void BuildMatrix_Yuv2Rgb_core(double Kr, double Kb, int int_arith_shift, bool full_scale_s, bool full_scale_d, int bits_per_pixel, ConversionMatrix& matrix) | |
| 211 | { | ||
| 212 | float Sy_f, Suv_f, Oy_f, Orgb_f; | ||
| 213 | |||
| 214 | 115 | bits_conv_constants luma, chroma; | |
| 215 | 115 | bits_conv_constants luma_to_32bit; | |
| 216 | |||
| 217 | // helpers for post-matrix conversion to 32-bit float (for high bit depth sources or targets, e.g. 16-bit to 32-bit float) | ||
| 218 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 24 taken 115 times.
|
115 | get_bits_conv_constants(luma_to_32bit, false, full_scale_s, full_scale_d, bits_per_pixel, 32); |
| 219 | 115 | matrix.target_span_f_32 = luma_to_32bit.dst_span; | |
| 220 | 115 | matrix.offset_out_f_32 = luma_to_32bit.dst_offset; | |
| 221 | |||
| 222 | // We use dstBitDepth = srcBitDepth because the matrix handles the magnitude | ||
| 223 | // via the mulfac and Srgb calculations. We just need the standardized spans. | ||
| 224 |
1/2✗ Branch 54 → 55 not taken.
✓ Branch 54 → 76 taken 115 times.
|
115 | get_bits_conv_constants(luma, false, full_scale_s, full_scale_d, bits_per_pixel, bits_per_pixel); |
| 225 |
1/2✓ Branch 106 → 107 taken 115 times.
✗ Branch 106 → 128 not taken.
|
115 | get_bits_conv_constants(chroma, true, full_scale_s, full_scale_d, bits_per_pixel, bits_per_pixel); |
| 226 | |||
| 227 | 115 | matrix.target_span_f = luma.dst_span; | |
| 228 | |||
| 229 | 115 | Sy_f = luma.src_span; | |
| 230 | 115 | Suv_f = chroma.src_span; | |
| 231 | 115 | Oy_f = luma.src_offset; | |
| 232 | 115 | Orgb_f = luma.dst_offset; | |
| 233 | |||
| 234 | /* | ||
| 235 | Kr = {0.299, 0.2126} | ||
| 236 | Kb = {0.114, 0.0722} | ||
| 237 | Kg = 1 - Kr - Kb // {0.587, 0.7152} | ||
| 238 | Srgb = 255 | ||
| 239 | Sy = {219, 255} // { 235-16, 255-0 } | ||
| 240 | Suv = {112, 127} // { (240-16)/2, (255-0)/2 } | ||
| 241 | Oy = {16, 0} | ||
| 242 | Ouv = 128 | ||
| 243 | |||
| 244 | Y =(y-Oy) / Sy // 0..1 | ||
| 245 | U =(u-Ouv) / Suv //-1..1 | ||
| 246 | V =(v-Ouv) / Suv | ||
| 247 | |||
| 248 | R = Y + V*(1-Kr) // 0..1 | ||
| 249 | G = Y - U*(1-Kb)*Kb/Kg - V*(1-Kr)*Kr/Kg | ||
| 250 | B = Y + U*(1-Kb) | ||
| 251 | |||
| 252 | r = R*Srgb // 0..255 0..65535 | ||
| 253 | g = G*Srgb | ||
| 254 | b = B*Srgb | ||
| 255 | */ | ||
| 256 | |||
| 257 | |||
| 258 | 115 | const double mulfac = (double)(1 << int_arith_shift); // integer aritmetic precision scale | |
| 259 | |||
| 260 | 115 | const double Kg = 1. - Kr - Kb; | |
| 261 | |||
| 262 | // The Srgb (destination span) is also just the dst_span (RGB is luma-like)! | ||
| 263 | 115 | const float Srgb_f = (float)luma.dst_span; | |
| 264 | |||
| 265 | // symmetric rounding for both positive and negative coefficients | ||
| 266 | 1265 | auto round_coeff = [](double v) { | |
| 267 |
2/2✓ Branch 2 → 3 taken 978 times.
✓ Branch 2 → 4 taken 287 times.
|
1265 | return (int)(v >= 0 ? (v + 0.5) : (v - 0.5)); |
| 268 | }; | ||
| 269 | |||
| 270 | 115 | double y_b_f = (Srgb_f * 1.000 / Sy_f); //Y | |
| 271 | 115 | double u_b_f = (Srgb_f * (1 - Kb) / Suv_f); //U | |
| 272 | 115 | double v_b_f = (Srgb_f * 0.000 / Suv_f); //V | |
| 273 | 115 | double y_g_f = (Srgb_f * 1.000 / Sy_f); | |
| 274 | 115 | double u_g_f = (Srgb_f * (Kb - 1) * Kb / Kg / Suv_f); | |
| 275 | 115 | double v_g_f = (Srgb_f * (Kr - 1) * Kr / Kg / Suv_f); | |
| 276 | 115 | double y_r_f = (Srgb_f * 1.000 / Sy_f); | |
| 277 | 115 | double u_r_f = (Srgb_f * 0.000 / Suv_f); | |
| 278 | 115 | double v_r_f = (Srgb_f * (1 - Kr) / Suv_f); | |
| 279 | 115 | double offset_y_f = -Oy_f; // negative, it will be added in the conversion, so we store the negative here | |
| 280 | 115 | double offset_rgb_f = Orgb_f; | |
| 281 | |||
| 282 | 115 | matrix.y_b_f = (float)(y_b_f); | |
| 283 | 115 | matrix.u_b_f = (float)(u_b_f); | |
| 284 | 115 | matrix.v_b_f = (float)(v_b_f); | |
| 285 | 115 | matrix.y_g_f = (float)(y_g_f); | |
| 286 | 115 | matrix.u_g_f = (float)(u_g_f); | |
| 287 | 115 | matrix.v_g_f = (float)(v_g_f); | |
| 288 | 115 | matrix.y_r_f = (float)(y_r_f); | |
| 289 | 115 | matrix.u_r_f = (float)(u_r_f); | |
| 290 | 115 | matrix.v_r_f = (float)(v_r_f); | |
| 291 | 115 | matrix.offset_y_f = (float)offset_y_f; | |
| 292 | 115 | matrix.offset_rgb_f = (float)offset_rgb_f; | |
| 293 | |||
| 294 | 115 | matrix.y_b = round_coeff(mulfac * y_b_f); | |
| 295 | 115 | matrix.u_b = round_coeff(mulfac * u_b_f); | |
| 296 | 115 | matrix.v_b = round_coeff(mulfac * v_b_f); | |
| 297 | 115 | matrix.y_g = round_coeff(mulfac * y_g_f); | |
| 298 | 115 | matrix.u_g = round_coeff(mulfac * u_g_f); | |
| 299 | 115 | matrix.v_g = round_coeff(mulfac * v_g_f); | |
| 300 | 115 | matrix.y_r = round_coeff(mulfac * y_r_f); | |
| 301 | 115 | matrix.u_r = round_coeff(mulfac * u_r_f); | |
| 302 | 115 | matrix.v_r = round_coeff(mulfac * v_r_f); | |
| 303 | 115 | matrix.offset_y = round_coeff(offset_y_f); | |
| 304 | 115 | matrix.offset_rgb = round_coeff(offset_rgb_f); | |
| 305 | |||
| 306 | // in: yuv. out: rgb | ||
| 307 | 115 | matrix.offset_in = matrix.offset_y; | |
| 308 | 115 | matrix.offset_in_f = matrix.offset_y_f; | |
| 309 | 115 | matrix.offset_out = matrix.offset_rgb; | |
| 310 | 115 | matrix.offset_out_f = matrix.offset_rgb_f; | |
| 311 | |||
| 312 | 115 | } | |
| 313 | |||
| 314 | 351 | bool GetKrKb(int matrix, double& Kr, double& Kb) | |
| 315 | { | ||
| 316 |
7/7✓ Branch 2 → 3 taken 101 times.
✓ Branch 2 → 4 taken 139 times.
✓ Branch 2 → 5 taken 47 times.
✓ Branch 2 → 6 taken 18 times.
✓ Branch 2 → 7 taken 21 times.
✓ Branch 2 → 8 taken 9 times.
✓ Branch 2 → 9 taken 16 times.
|
351 | switch (matrix) { |
| 317 | 101 | case AVS_MATRIX_BT470_BG: | |
| 318 | 101 | case AVS_MATRIX_ST170_M: Kr = 0.299; Kb = 0.114; return true; | |
| 319 | 139 | case AVS_MATRIX_BT709: Kr = 0.2126; Kb = 0.0722; return true; | |
| 320 | 47 | case AVS_MATRIX_BT2020_NCL: | |
| 321 | 47 | case AVS_MATRIX_BT2020_CL: Kr = 0.2627; Kb = 0.0593; return true; | |
| 322 | 18 | case AVS_MATRIX_BT470_M: Kr = 0.3; Kb = 0.11; return true; | |
| 323 | 21 | case AVS_MATRIX_ST240_M: Kr = 0.212; Kb = 0.087; return true; | |
| 324 | 9 | case AVS_MATRIX_AVERAGE: Kr = 1.0 / 3; Kb = 1.0 / 3; return true; | |
| 325 | 16 | default: return false; | |
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | 227 | bool do_BuildMatrix_Rgb2Yuv(int _Matrix, int _ColorRange, int _ColorRange_Out, int int_arith_shift, int bits_per_pixel, ConversionMatrix& matrix) | |
| 330 | { | ||
| 331 |
4/4✓ Branch 2 → 3 taken 110 times.
✓ Branch 2 → 5 taken 117 times.
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 5 taken 107 times.
|
227 | if (_ColorRange != ColorRange_Compat_e::AVS_COLORRANGE_FULL && _ColorRange != ColorRange_Compat_e::AVS_COLORRANGE_LIMITED) |
| 332 | 3 | return false; | |
| 333 |
4/4✓ Branch 5 → 6 taken 121 times.
✓ Branch 5 → 8 taken 103 times.
✓ Branch 6 → 7 taken 3 times.
✓ Branch 6 → 8 taken 118 times.
|
224 | if (_ColorRange_Out != ColorRange_Compat_e::AVS_COLORRANGE_FULL && _ColorRange_Out != ColorRange_Compat_e::AVS_COLORRANGE_LIMITED) |
| 334 | 3 | return false; | |
| 335 | |||
| 336 | 221 | const bool is_full_s = _ColorRange == ColorRange_Compat_e::AVS_COLORRANGE_FULL; | |
| 337 | 221 | const bool is_full_d = _ColorRange_Out == ColorRange_Compat_e::AVS_COLORRANGE_FULL; | |
| 338 | |||
| 339 | // Special cases not handled by GetKrKb | ||
| 340 |
2/2✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 11 taken 219 times.
|
221 | if (_Matrix == Matrix_e::AVS_MATRIX_RGB) { |
| 341 | // copies Green to Y and sets UV to 0 | ||
| 342 | 2 | BuildMatrix_Rgb2Yuv_core(0.0, 0.0, int_arith_shift, is_full_s, is_full_d, bits_per_pixel, matrix); | |
| 343 | 2 | return true; | |
| 344 | } | ||
| 345 |
4/4✓ Branch 11 → 12 taken 218 times.
✓ Branch 11 → 13 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 14 taken 217 times.
|
219 | if (_Matrix == Matrix_e::AVS_MATRIX_ICTCP || _Matrix == Matrix_e::AVS_MATRIX_YCGCO) |
| 346 | 2 | return false; // not supported | |
| 347 | |||
| 348 | double Kr, Kb; | ||
| 349 |
2/2✓ Branch 15 → 16 taken 4 times.
✓ Branch 15 → 17 taken 213 times.
|
217 | if (!GetKrKb(_Matrix, Kr, Kb)) |
| 350 | 4 | return false; | |
| 351 | |||
| 352 | 213 | BuildMatrix_Rgb2Yuv_core(Kr, Kb, int_arith_shift, is_full_s, is_full_d, bits_per_pixel, matrix); | |
| 353 | 213 | return true; | |
| 354 | } | ||
| 355 | |||
| 356 | 127 | bool do_BuildMatrix_Yuv2Rgb(int _Matrix, int _ColorRange, int _ColorRange_Out, int int_arith_shift, int bits_per_pixel, ConversionMatrix& matrix) | |
| 357 | { | ||
| 358 |
4/4✓ Branch 2 → 3 taken 65 times.
✓ Branch 2 → 5 taken 62 times.
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 5 taken 62 times.
|
127 | if (_ColorRange != ColorRange_Compat_e::AVS_COLORRANGE_FULL && _ColorRange != ColorRange_Compat_e::AVS_COLORRANGE_LIMITED) |
| 359 | 3 | return false; | |
| 360 |
4/4✓ Branch 5 → 6 taken 56 times.
✓ Branch 5 → 8 taken 68 times.
✓ Branch 6 → 7 taken 3 times.
✓ Branch 6 → 8 taken 53 times.
|
124 | if (_ColorRange_Out != ColorRange_Compat_e::AVS_COLORRANGE_FULL && _ColorRange_Out != ColorRange_Compat_e::AVS_COLORRANGE_LIMITED) |
| 361 | 3 | return false; | |
| 362 | |||
| 363 | 121 | const bool is_full_s = _ColorRange == ColorRange_Compat_e::AVS_COLORRANGE_FULL; | |
| 364 | 121 | const bool is_full_d = _ColorRange_Out == ColorRange_Compat_e::AVS_COLORRANGE_FULL; | |
| 365 | |||
| 366 | // Special cases not handled by GetKrKb | ||
| 367 |
2/2✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 11 taken 120 times.
|
121 | if (_Matrix == Matrix_e::AVS_MATRIX_RGB) { |
| 368 | 1 | BuildMatrix_Yuv2Rgb_core(0.0, 0.0, int_arith_shift, is_full_s, is_full_d, bits_per_pixel, matrix); | |
| 369 | 1 | return true; | |
| 370 | } | ||
| 371 |
4/4✓ Branch 11 → 12 taken 119 times.
✓ Branch 11 → 13 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 14 taken 118 times.
|
120 | if (_Matrix == Matrix_e::AVS_MATRIX_ICTCP || _Matrix == Matrix_e::AVS_MATRIX_YCGCO) |
| 372 | 2 | return false; // not supported | |
| 373 | |||
| 374 | double Kr, Kb; | ||
| 375 |
2/2✓ Branch 15 → 16 taken 4 times.
✓ Branch 15 → 17 taken 114 times.
|
118 | if (!GetKrKb(_Matrix, Kr, Kb)) |
| 376 | 4 | return false; | |
| 377 | |||
| 378 | 114 | BuildMatrix_Yuv2Rgb_core(Kr, Kb, int_arith_shift, is_full_s, is_full_d, bits_per_pixel, matrix); | |
| 379 | 114 | return true; | |
| 380 | } | ||
| 381 |