filters/focus.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 "focus.h" | ||
| 36 | #ifdef INTEL_INTRINSICS | ||
| 37 | #include "intel/focus_sse.h" | ||
| 38 | #include "intel/focus_avx2.h" | ||
| 39 | #endif | ||
| 40 | #include <cmath> | ||
| 41 | #include <vector> | ||
| 42 | #include <avs/alignment.h> | ||
| 43 | #include <avs/minmax.h> | ||
| 44 | #include "../core/internal.h" | ||
| 45 | #include <stdint.h> | ||
| 46 | |||
| 47 | |||
| 48 | /******************************************************************** | ||
| 49 | ***** Declare index of new filters for Avisynth's filter engine ***** | ||
| 50 | ********************************************************************/ | ||
| 51 | |||
| 52 | extern const AVSFunction Focus_filters[] = { | ||
| 53 | { "Blur", BUILTIN_FUNC_PREFIX, "cf[]f[mmx]b", Create_Blur }, // amount [-1.0 - 1.5849625] -- log2(3) | ||
| 54 | { "Sharpen", BUILTIN_FUNC_PREFIX, "cf[]f[mmx]b", Create_Sharpen }, // amount [-1.5849625 - 1.0] | ||
| 55 | { "TemporalSoften", BUILTIN_FUNC_PREFIX, "ciii[scenechange]i[mode]i", TemporalSoften::Create }, // radius, luma_threshold, chroma_threshold | ||
| 56 | { "SpatialSoften", BUILTIN_FUNC_PREFIX, "ciii", SpatialSoften::Create }, // radius, luma_threshold, chroma_threshold | ||
| 57 | { 0 } | ||
| 58 | }; | ||
| 59 | |||
| 60 | |||
| 61 | |||
| 62 | |||
| 63 | |||
| 64 | /**************************************** | ||
| 65 | *** AdjustFocus helper classes *** | ||
| 66 | *** Originally by Ben R.G. *** | ||
| 67 | *** MMX code by Marc FD *** | ||
| 68 | *** Adaptation and bugfixes sh0dan *** | ||
| 69 | *** Code actually requires ISSE! *** | ||
| 70 | *** Not anymore - pure MMX IanB *** | ||
| 71 | *** Implement boundary proc. IanB *** | ||
| 72 | *** Impl. full 8bit MMX proc. IanB *** | ||
| 73 | ***************************************/ | ||
| 74 | |||
| 75 | ✗ | AdjustFocusV::AdjustFocusV(double _amount, PClip _child) | |
| 76 | ✗ | : GenericVideoFilter(_child), amountd(pow(2.0, _amount)) { | |
| 77 | ✗ | half_amount = int(32768 * amountd + 0.5); | |
| 78 | ✗ | } | |
| 79 | |||
| 80 | template<typename pixel_t> | ||
| 81 | ✗ | static void af_vertical_c(BYTE* line_buf8, BYTE* dstp8, const int height, const int pitch8, const int width, const int half_amount, int bits_per_pixel) { | |
| 82 | typedef typename std::conditional < sizeof(pixel_t) == 1, int, int64_t>::type weight_t; | ||
| 83 | // kernel:[(1-1/2^_amount)/2, 1/2^_amount, (1-1/2^_amount)/2] | ||
| 84 | ✗ | weight_t center_weight = half_amount*2; // *2: 16 bit scaled arithmetic, but the converted amount parameter scaled is only 15 bits | |
| 85 | ✗ | weight_t outer_weight = 32768-half_amount; // (1-1/2^_amount)/2 32768 = 0.5 | |
| 86 | ✗ | int max_pixel_value = (1 << bits_per_pixel) - 1; | |
| 87 | |||
| 88 | ✗ | pixel_t * dstp = reinterpret_cast<pixel_t *>(dstp8); | |
| 89 | ✗ | pixel_t * line_buf = reinterpret_cast<pixel_t *>(line_buf8); | |
| 90 | ✗ | int pitch = pitch8 / sizeof(pixel_t); | |
| 91 | |||
| 92 | ✗ | for (int y = height-1; y>0; --y) { | |
| 93 | ✗ | for (int x = 0; x < width; ++x) { | |
| 94 | pixel_t a; | ||
| 95 | // Note: ScaledPixelClip is overloaded. With int64_t parameter and uint16_t result works for 16 bit | ||
| 96 | if constexpr(sizeof(pixel_t) == 1) | ||
| 97 | ✗ | a = ScaledPixelClip((weight_t)(dstp[x] * center_weight + (line_buf[x] + dstp[x+pitch]) * outer_weight)); | |
| 98 | else | ||
| 99 | ✗ | a = (pixel_t)ScaledPixelClipEx((weight_t)(dstp[x] * center_weight + (line_buf[x] + dstp[x+pitch]) * outer_weight), max_pixel_value); | |
| 100 | ✗ | line_buf[x] = dstp[x]; | |
| 101 | ✗ | dstp[x] = a; | |
| 102 | } | ||
| 103 | ✗ | dstp += pitch; | |
| 104 | } | ||
| 105 | ✗ | for (int x = 0; x < width; ++x) { // Last row - map centre as lower | |
| 106 | if constexpr(sizeof(pixel_t) == 1) | ||
| 107 | ✗ | dstp[x] = ScaledPixelClip((weight_t)(dstp[x] * center_weight + (line_buf[x] + dstp[x]) * outer_weight)); | |
| 108 | else | ||
| 109 | ✗ | dstp[x] = (pixel_t)ScaledPixelClipEx((weight_t)(dstp[x] * center_weight + (line_buf[x] + dstp[x]) * outer_weight), max_pixel_value); | |
| 110 | } | ||
| 111 | ✗ | } | |
| 112 | |||
| 113 | ✗ | static void af_vertical_c_float(BYTE* line_buf8, BYTE* dstp8, const int height, const int pitch8, const int width, const float amount) { | |
| 114 | ✗ | float *dstp = reinterpret_cast<float *>(dstp8); | |
| 115 | ✗ | float *line_buf = reinterpret_cast<float *>(line_buf8); | |
| 116 | ✗ | int pitch = pitch8 / sizeof(float); | |
| 117 | |||
| 118 | ✗ | const float center_weight = amount; | |
| 119 | ✗ | const float outer_weight = (1.0f - amount) / 2.0f; | |
| 120 | |||
| 121 | ✗ | for (int y = height-1; y>0; --y) { | |
| 122 | ✗ | for (int x = 0; x < width; ++x) { | |
| 123 | ✗ | float a = dstp[x] * center_weight + (line_buf[x] + dstp[x+pitch]) * outer_weight; | |
| 124 | ✗ | line_buf[x] = dstp[x]; | |
| 125 | ✗ | dstp[x] = a; | |
| 126 | } | ||
| 127 | ✗ | dstp += pitch; | |
| 128 | } | ||
| 129 | ✗ | for (int x = 0; x < width; ++x) { // Last row - map centre as lower | |
| 130 | ✗ | dstp[x] = dstp[x] * center_weight + (line_buf[x] + dstp[x]) * outer_weight; | |
| 131 | } | ||
| 132 | ✗ | } | |
| 133 | |||
| 134 | template<typename pixel_t> | ||
| 135 | ✗ | static void af_vertical_process(BYTE* line_buf, BYTE* dstp, size_t height, size_t pitch, size_t row_size, int half_amount, int bits_per_pixel, IScriptEnvironment* env) { | |
| 136 | ✗ | size_t width = row_size / sizeof(pixel_t); | |
| 137 | // only for 8/16 bit, float separated | ||
| 138 | #ifdef INTEL_INTRINSICS | ||
| 139 | ✗ | if (sizeof(pixel_t) == 1 && (env->GetCPUFlags() & CPUF_AVX2) && width >= 32) { | |
| 140 | //pitch of aligned frames is always >= 32 so we'll just process some garbage if width is not mod32 | ||
| 141 | ✗ | af_vertical_avx2(line_buf, dstp, (int)height, (int)pitch, (int)width, half_amount); | |
| 142 | } | ||
| 143 | else | ||
| 144 | ✗ | if (sizeof(pixel_t) == 1 && (env->GetCPUFlags() & CPUF_SSE2) && width >= 16) { | |
| 145 | //pitch of aligned frames is always >= 16 so we'll just process some garbage if width is not mod16 | ||
| 146 | ✗ | af_vertical_sse2(line_buf, dstp, (int)height, (int)pitch, (int)width, half_amount); | |
| 147 | } | ||
| 148 | ✗ | else if (sizeof(pixel_t) == 2 && (env->GetCPUFlags() & CPUF_AVX2) && row_size >= 32) { | |
| 149 | ✗ | af_vertical_uint16_t_avx2(line_buf, dstp, (int)height, (int)pitch, (int)row_size, half_amount); | |
| 150 | } | ||
| 151 | ✗ | else if (sizeof(pixel_t) == 2 && (env->GetCPUFlags() & CPUF_SSE4_1) && row_size >= 16) { | |
| 152 | ✗ | af_vertical_uint16_t_sse41(line_buf, dstp, (int)height, (int)pitch, (int)row_size, half_amount); | |
| 153 | } | ||
| 154 | ✗ | else if (sizeof(pixel_t) == 2 && (env->GetCPUFlags() & CPUF_SSE2) && row_size >= 16) { | |
| 155 | ✗ | af_vertical_uint16_t_sse2(line_buf, dstp, (int)height, (int)pitch, (int)row_size, half_amount); | |
| 156 | } | ||
| 157 | else | ||
| 158 | #ifdef X86_32 | ||
| 159 | if (sizeof(pixel_t) == 1 && (env->GetCPUFlags() & CPUF_MMX) && width >= 8) | ||
| 160 | { | ||
| 161 | size_t mod8_width = width / 8 * 8; | ||
| 162 | af_vertical_mmx(line_buf, dstp, height, pitch, mod8_width, half_amount); | ||
| 163 | if (mod8_width != width) { | ||
| 164 | //yes, this is bad for caching. MMX shouldn't be used these days anyway | ||
| 165 | af_vertical_c<uint8_t>(line_buf, dstp + mod8_width, height, pitch, width - mod8_width, half_amount, bits_per_pixel); | ||
| 166 | } | ||
| 167 | } else | ||
| 168 | #endif | ||
| 169 | #endif | ||
| 170 | { | ||
| 171 | ✗ | af_vertical_c<pixel_t>(line_buf, dstp, (int)height, (int)pitch, (int)width, half_amount, bits_per_pixel); | |
| 172 | } | ||
| 173 | ✗ | } | |
| 174 | |||
| 175 | ✗ | static void af_vertical_process_float(BYTE* line_buf, BYTE* dstp, size_t height, size_t pitch, size_t row_size, double amountd, IScriptEnvironment* env) { | |
| 176 | ✗ | size_t width = row_size / sizeof(float); | |
| 177 | #ifdef INTEL_INTRINSICS | ||
| 178 | ✗ | if ((env->GetCPUFlags() & CPUF_SSE2) && width >= 16) { | |
| 179 | //pitch of aligned frames is always >= 16 so we'll just process some garbage if width is not mod16 | ||
| 180 | ✗ | af_vertical_sse2_float(line_buf, dstp, (int)height, (int)pitch, (int)row_size, (float)amountd); | |
| 181 | } | ||
| 182 | else | ||
| 183 | #endif | ||
| 184 | { | ||
| 185 | ✗ | af_vertical_c_float(line_buf, dstp, (int)height, (int)pitch, (int)width, (float)amountd); | |
| 186 | } | ||
| 187 | ✗ | } | |
| 188 | |||
| 189 | // -------------------------------- | ||
| 190 | // Vertical Blur/Sharpen | ||
| 191 | // -------------------------------- | ||
| 192 | |||
| 193 | ✗ | PVideoFrame __stdcall AdjustFocusV::GetFrame(int n, IScriptEnvironment* env) | |
| 194 | { | ||
| 195 | ✗ | PVideoFrame src = child->GetFrame(n, env); | |
| 196 | |||
| 197 | ✗ | env->MakeWritable(&src); | |
| 198 | |||
| 199 | ✗ | BYTE* line_buf = reinterpret_cast<BYTE*>(env->Allocate(AlignNumber(src->GetRowSize(), FRAME_ALIGN), FRAME_ALIGN, AVS_POOLED_ALLOC)); | |
| 200 | ✗ | if (!line_buf) { | |
| 201 | ✗ | env->ThrowError("AdjustFocusV: Could not reserve memory."); | |
| 202 | } | ||
| 203 | |||
| 204 | ✗ | int pixelsize = vi.ComponentSize(); | |
| 205 | ✗ | int bits_per_pixel = vi.BitsPerComponent(); | |
| 206 | |||
| 207 | ✗ | if (vi.IsPlanar()) { | |
| 208 | ✗ | const int planesYUV[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A}; | |
| 209 | ✗ | const int planesRGB[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A}; | |
| 210 | ✗ | const int *planes = vi.IsYUV() || vi.IsYUVA() ? planesYUV : planesRGB; | |
| 211 | |||
| 212 | ✗ | for (int cplane = 0; cplane < 3; cplane++) { | |
| 213 | ✗ | int plane = planes[cplane]; | |
| 214 | ✗ | BYTE* dstp = src->GetWritePtr(plane); | |
| 215 | ✗ | int pitch = src->GetPitch(plane); | |
| 216 | ✗ | int row_size = src->GetRowSize(plane); | |
| 217 | ✗ | int height = src->GetHeight(plane); | |
| 218 | ✗ | memcpy(line_buf, dstp, row_size); // First row - map centre as upper | |
| 219 | |||
| 220 | ✗ | switch (pixelsize) { | |
| 221 | ✗ | case 1: af_vertical_process<uint8_t>(line_buf, dstp, height, pitch, row_size, half_amount, bits_per_pixel, env); break; | |
| 222 | ✗ | case 2: af_vertical_process<uint16_t>(line_buf, dstp, height, pitch, row_size, half_amount, bits_per_pixel, env); break; | |
| 223 | ✗ | default: // 4: float | |
| 224 | ✗ | af_vertical_process_float(line_buf, dstp, height, pitch, row_size, amountd, env); break; | |
| 225 | } | ||
| 226 | } | ||
| 227 | } | ||
| 228 | else { | ||
| 229 | ✗ | BYTE* dstp = src->GetWritePtr(); | |
| 230 | ✗ | int pitch = src->GetPitch(); | |
| 231 | ✗ | int row_size = vi.RowSize(); | |
| 232 | ✗ | int height = vi.height; | |
| 233 | ✗ | memcpy(line_buf, dstp, row_size); // First row - map centre as upper | |
| 234 | ✗ | if (pixelsize == 1) | |
| 235 | ✗ | af_vertical_process<uint8_t>(line_buf, dstp, height, pitch, row_size, half_amount, bits_per_pixel, env); | |
| 236 | else | ||
| 237 | ✗ | af_vertical_process<uint16_t>(line_buf, dstp, height, pitch, row_size, half_amount, bits_per_pixel, env); | |
| 238 | } | ||
| 239 | |||
| 240 | ✗ | env->Free(line_buf); | |
| 241 | ✗ | return src; | |
| 242 | ✗ | } | |
| 243 | |||
| 244 | |||
| 245 | ✗ | AdjustFocusH::AdjustFocusH(double _amount, PClip _child) | |
| 246 | ✗ | : GenericVideoFilter(_child), amountd(pow(2.0, _amount)) { | |
| 247 | ✗ | half_amount = int(32768 * amountd + 0.5); | |
| 248 | ✗ | } | |
| 249 | |||
| 250 | |||
| 251 | // -------------------------------------- | ||
| 252 | // Blur/Sharpen Horizontal RGB32 C++ Code | ||
| 253 | // -------------------------------------- | ||
| 254 | |||
| 255 | template<typename pixel_t, typename weight_t> | ||
| 256 | static AVS_FORCEINLINE void af_horizontal_rgb32_process_line_c(pixel_t b_left, pixel_t g_left, pixel_t r_left, pixel_t a_left, pixel_t *dstp, size_t width, weight_t center_weight, weight_t outer_weight) { | ||
| 257 | size_t x; | ||
| 258 | ✗ | for (x = 0; x < width-1; ++x) | |
| 259 | { | ||
| 260 | ✗ | pixel_t b = ScaledPixelClip((weight_t)(dstp[x*4+0] * center_weight + (b_left + dstp[x*4+4]) * outer_weight)); | |
| 261 | ✗ | b_left = dstp[x*4+0]; | |
| 262 | ✗ | dstp[x*4+0] = b; | |
| 263 | ✗ | pixel_t g = ScaledPixelClip((weight_t)(dstp[x*4+1] * center_weight + (g_left + dstp[x*4+5]) * outer_weight)); | |
| 264 | ✗ | g_left = dstp[x*4+1]; | |
| 265 | ✗ | dstp[x*4+1] = g; | |
| 266 | ✗ | pixel_t r = ScaledPixelClip((weight_t)(dstp[x*4+2] * center_weight + (r_left + dstp[x*4+6]) * outer_weight)); | |
| 267 | ✗ | r_left = dstp[x*4+2]; | |
| 268 | ✗ | dstp[x*4+2] = r; | |
| 269 | ✗ | pixel_t a = ScaledPixelClip((weight_t)(dstp[x*4+3] * center_weight + (a_left + dstp[x*4+7]) * outer_weight)); | |
| 270 | ✗ | a_left = dstp[x*4+3]; | |
| 271 | ✗ | dstp[x*4+3] = a; | |
| 272 | } | ||
| 273 | ✗ | dstp[x*4+0] = ScaledPixelClip((weight_t)(dstp[x*4+0] * center_weight + (b_left + dstp[x*4+0]) * outer_weight)); | |
| 274 | ✗ | dstp[x*4+1] = ScaledPixelClip((weight_t)(dstp[x*4+1] * center_weight + (g_left + dstp[x*4+1]) * outer_weight)); | |
| 275 | ✗ | dstp[x*4+2] = ScaledPixelClip((weight_t)(dstp[x*4+2] * center_weight + (r_left + dstp[x*4+2]) * outer_weight)); | |
| 276 | ✗ | dstp[x*4+3] = ScaledPixelClip((weight_t)(dstp[x*4+3] * center_weight + (a_left + dstp[x*4+3]) * outer_weight)); | |
| 277 | ✗ | } | |
| 278 | |||
| 279 | template<typename pixel_t> | ||
| 280 | ✗ | static void af_horizontal_rgb32_64_c(BYTE* dstp8, size_t height, size_t pitch8, size_t width, int half_amount) { | |
| 281 | typedef typename std::conditional < sizeof(pixel_t) == 1, int, int64_t>::type weight_t; | ||
| 282 | // kernel:[(1-1/2^_amount)/2, 1/2^_amount, (1-1/2^_amount)/2] | ||
| 283 | ✗ | weight_t center_weight = half_amount*2; // *2: 16 bit scaled arithmetic, but the converted amount parameter scaled is only 15 bits | |
| 284 | ✗ | weight_t outer_weight = 32768-half_amount; // (1-1/2^_amount)/2 32768 = 0.5 | |
| 285 | |||
| 286 | ✗ | pixel_t* dstp = reinterpret_cast<pixel_t *>(dstp8); | |
| 287 | ✗ | size_t pitch = pitch8 / sizeof(pixel_t); | |
| 288 | |||
| 289 | ✗ | for (size_t y = height; y>0; --y) | |
| 290 | { | ||
| 291 | ✗ | pixel_t b_left = dstp[0]; | |
| 292 | ✗ | pixel_t g_left = dstp[1]; | |
| 293 | ✗ | pixel_t r_left = dstp[2]; | |
| 294 | ✗ | pixel_t a_left = dstp[3]; | |
| 295 | ✗ | af_horizontal_rgb32_process_line_c<pixel_t, weight_t>(b_left, g_left, r_left, a_left, dstp, width, center_weight, outer_weight); | |
| 296 | ✗ | dstp += pitch; | |
| 297 | } | ||
| 298 | |||
| 299 | ✗ | } | |
| 300 | |||
| 301 | |||
| 302 | // ------------------------------------- | ||
| 303 | // Blur/Sharpen Horizontal YUY2 C++ Code | ||
| 304 | // ------------------------------------- | ||
| 305 | |||
| 306 | ✗ | static void af_horizontal_yuy2_c(BYTE* p, int height, int pitch, int width, int amount) { | |
| 307 | ✗ | const int center_weight = amount*2; | |
| 308 | ✗ | const int outer_weight = 32768-amount; | |
| 309 | ✗ | for (int y0 = height; y0>0; --y0) | |
| 310 | { | ||
| 311 | ✗ | BYTE yy = p[0]; | |
| 312 | ✗ | BYTE uv = p[1]; | |
| 313 | ✗ | BYTE vu = p[3]; | |
| 314 | int x; | ||
| 315 | ✗ | for (x = 0; x < width-2; ++x) | |
| 316 | { | ||
| 317 | ✗ | BYTE y = ScaledPixelClip(p[x*2+0] * center_weight + (yy + p[x*2+2]) * outer_weight); | |
| 318 | ✗ | yy = p[x*2+0]; | |
| 319 | ✗ | p[x*2+0] = y; | |
| 320 | ✗ | BYTE w = ScaledPixelClip(p[x*2+1] * center_weight + (uv + p[x*2+5]) * outer_weight); | |
| 321 | ✗ | uv = vu; | |
| 322 | ✗ | vu = p[x*2+1]; | |
| 323 | ✗ | p[x*2+1] = w; | |
| 324 | } | ||
| 325 | ✗ | BYTE y = ScaledPixelClip(p[x*2+0] * center_weight + (yy + p[x*2+2]) * outer_weight); | |
| 326 | ✗ | yy = p[x*2+0]; | |
| 327 | ✗ | p[x*2+0] = y; | |
| 328 | ✗ | p[x*2+1] = ScaledPixelClip(p[x*2+1] * center_weight + (uv + p[x*2+1]) * outer_weight); | |
| 329 | ✗ | p[x*2+2] = ScaledPixelClip(p[x*2+2] * center_weight + (yy + p[x*2+2]) * outer_weight); | |
| 330 | ✗ | p[x*2+3] = ScaledPixelClip(p[x*2+3] * center_weight + (vu + p[x*2+3]) * outer_weight); | |
| 331 | |||
| 332 | ✗ | p += pitch; | |
| 333 | } | ||
| 334 | ✗ | } | |
| 335 | |||
| 336 | |||
| 337 | // -------------------------------------- | ||
| 338 | // Blur/Sharpen Horizontal RGB24 C++ Code | ||
| 339 | // -------------------------------------- | ||
| 340 | |||
| 341 | template<typename pixel_t> | ||
| 342 | ✗ | static void af_horizontal_rgb24_48_c(BYTE* dstp8, int height, int pitch8, int width, int half_amount) { | |
| 343 | typedef typename std::conditional < sizeof(pixel_t) == 1, int, int64_t>::type weight_t; | ||
| 344 | // kernel:[(1-1/2^_amount)/2, 1/2^_amount, (1-1/2^_amount)/2] | ||
| 345 | ✗ | weight_t center_weight = half_amount*2; // *2: 16 bit scaled arithmetic, but the converted amount parameter scaled is only 15 bits | |
| 346 | ✗ | weight_t outer_weight = 32768-half_amount; // (1-1/2^_amount)/2 32768 = 0.5 | |
| 347 | |||
| 348 | ✗ | pixel_t *dstp = reinterpret_cast<pixel_t *>(dstp8); | |
| 349 | ✗ | int pitch = pitch8 / sizeof(pixel_t); | |
| 350 | ✗ | for (int y = height; y>0; --y) | |
| 351 | { | ||
| 352 | ✗ | pixel_t bb = dstp[0]; | |
| 353 | ✗ | pixel_t gg = dstp[1]; | |
| 354 | ✗ | pixel_t rr = dstp[2]; | |
| 355 | int x; | ||
| 356 | ✗ | for (x = 0; x < width-1; ++x) | |
| 357 | { | ||
| 358 | // ScaledPixelClip has 2 overloads: BYTE/uint16_t (int/int64 i) | ||
| 359 | ✗ | pixel_t b = ScaledPixelClip((weight_t)(dstp[x*3+0] * center_weight + (bb + dstp[x*3+3]) * outer_weight)); | |
| 360 | ✗ | bb = dstp[x*3+0]; dstp[x*3+0] = b; | |
| 361 | ✗ | pixel_t g = ScaledPixelClip((weight_t)(dstp[x*3+1] * center_weight + (gg + dstp[x*3+4]) * outer_weight)); | |
| 362 | ✗ | gg = dstp[x*3+1]; dstp[x*3+1] = g; | |
| 363 | ✗ | pixel_t r = ScaledPixelClip((weight_t)(dstp[x*3+2] * center_weight + (rr + dstp[x*3+5]) * outer_weight)); | |
| 364 | ✗ | rr = dstp[x*3+2]; dstp[x*3+2] = r; | |
| 365 | } | ||
| 366 | ✗ | dstp[x*3+0] = ScaledPixelClip((weight_t)(dstp[x*3+0] * center_weight + (bb + dstp[x*3+0]) * outer_weight)); | |
| 367 | ✗ | dstp[x*3+1] = ScaledPixelClip((weight_t)(dstp[x*3+1] * center_weight + (gg + dstp[x*3+1]) * outer_weight)); | |
| 368 | ✗ | dstp[x*3+2] = ScaledPixelClip((weight_t)(dstp[x*3+2] * center_weight + (rr + dstp[x*3+2]) * outer_weight)); | |
| 369 | ✗ | dstp += pitch; | |
| 370 | } | ||
| 371 | ✗ | } | |
| 372 | |||
| 373 | // ------------------------------------- | ||
| 374 | // Blur/Sharpen Horizontal YV12 C++ Code | ||
| 375 | // ------------------------------------- | ||
| 376 | |||
| 377 | // for linker reasons these forceinlined functions appear in C, intel sse2 and avx2 source as well | ||
| 378 | template<typename pixel_t> | ||
| 379 | static AVS_FORCEINLINE void af_horizontal_planar_process_line_c(pixel_t left, BYTE *dstp8, size_t row_size, int center_weight, int outer_weight) { | ||
| 380 | size_t x; | ||
| 381 | ✗ | pixel_t* dstp = reinterpret_cast<pixel_t *>(dstp8); | |
| 382 | typedef typename std::conditional < sizeof(pixel_t) == 1, int, int64_t>::type weight_t; // for calling the right ScaledPixelClip() | ||
| 383 | ✗ | size_t width = row_size / sizeof(pixel_t); | |
| 384 | ✗ | for (x = 0; x < width-1; ++x) { | |
| 385 | ✗ | pixel_t temp = ScaledPixelClip((weight_t)(dstp[x] * (weight_t)center_weight + (left + dstp[x+1]) * (weight_t)outer_weight)); | |
| 386 | ✗ | left = dstp[x]; | |
| 387 | ✗ | dstp[x] = temp; | |
| 388 | } | ||
| 389 | // ScaledPixelClip has 2 overloads: BYTE/uint16_t (int/int64 i) | ||
| 390 | ✗ | dstp[x] = ScaledPixelClip((weight_t)(dstp[x] * (weight_t)center_weight + (left + dstp[x]) * (weight_t)outer_weight)); | |
| 391 | ✗ | } | |
| 392 | |||
| 393 | static AVS_FORCEINLINE void af_horizontal_planar_process_line_uint16_c(uint16_t left, BYTE *dstp8, size_t row_size, int center_weight, int outer_weight, int bits_per_pixel) { | ||
| 394 | size_t x; | ||
| 395 | typedef uint16_t pixel_t; | ||
| 396 | ✗ | pixel_t* dstp = reinterpret_cast<pixel_t *>(dstp8); | |
| 397 | ✗ | const int max_pixel_value = (1 << bits_per_pixel) - 1; // clamping on 10-12-14-16 bitdepth | |
| 398 | typedef std::conditional < sizeof(pixel_t) == 1, int, int64_t>::type weight_t; // for calling the right ScaledPixelClip() | ||
| 399 | ✗ | size_t width = row_size / sizeof(pixel_t); | |
| 400 | ✗ | for (x = 0; x < width-1; ++x) { | |
| 401 | ✗ | pixel_t temp = (pixel_t)ScaledPixelClipEx((weight_t)(dstp[x] * (weight_t)center_weight + (left + dstp[x+1]) * (weight_t)outer_weight), max_pixel_value); | |
| 402 | ✗ | left = dstp[x]; | |
| 403 | ✗ | dstp[x] = temp; | |
| 404 | } | ||
| 405 | // ScaledPixelClip has 2 overloads: BYTE/uint16_t (int/int64 i) | ||
| 406 | ✗ | dstp[x] = ScaledPixelClipEx((weight_t)(dstp[x] * (weight_t)center_weight + (left + dstp[x]) * (weight_t)outer_weight), max_pixel_value); | |
| 407 | ✗ | } | |
| 408 | |||
| 409 | static AVS_FORCEINLINE void af_horizontal_planar_process_line_float_c(float left, float* dstp, size_t row_size, float center_weight, float outer_weight) { | ||
| 410 | size_t x; | ||
| 411 | ✗ | size_t width = row_size / sizeof(float); | |
| 412 | ✗ | for (x = 0; x < width - 1; ++x) { | |
| 413 | ✗ | float temp = dstp[x] * center_weight + (left + dstp[x + 1]) * outer_weight; | |
| 414 | ✗ | left = dstp[x]; | |
| 415 | ✗ | dstp[x] = temp; | |
| 416 | } | ||
| 417 | ✗ | dstp[x] = dstp[x] * center_weight + (left + dstp[x]) * outer_weight; | |
| 418 | ✗ | } | |
| 419 | |||
| 420 | template<typename pixel_t> | ||
| 421 | ✗ | static void af_horizontal_planar_c(BYTE* dstp8, size_t height, size_t pitch8, size_t row_size, size_t half_amount, int bits_per_pixel) | |
| 422 | { | ||
| 423 | ✗ | pixel_t* dstp = reinterpret_cast<pixel_t *>(dstp8); | |
| 424 | ✗ | size_t pitch = pitch8 / sizeof(pixel_t); | |
| 425 | ✗ | int center_weight = int(half_amount*2); | |
| 426 | ✗ | int outer_weight = int(32768-half_amount); | |
| 427 | pixel_t left; | ||
| 428 | ✗ | for (size_t y = height; y>0; --y) { | |
| 429 | ✗ | left = dstp[0]; | |
| 430 | if constexpr(sizeof(pixel_t) == 1) | ||
| 431 | ✗ | af_horizontal_planar_process_line_c<pixel_t>(left, (BYTE *)dstp, row_size, center_weight, outer_weight); | |
| 432 | else | ||
| 433 | ✗ | af_horizontal_planar_process_line_uint16_c(left, (BYTE *)dstp, row_size, center_weight, outer_weight, bits_per_pixel); | |
| 434 | ✗ | dstp += pitch; | |
| 435 | } | ||
| 436 | ✗ | } | |
| 437 | |||
| 438 | ✗ | static void af_horizontal_planar_float_c(BYTE* dstp8, size_t height, size_t pitch8, size_t row_size, float amount) | |
| 439 | { | ||
| 440 | ✗ | float* dstp = reinterpret_cast<float *>(dstp8); | |
| 441 | ✗ | size_t pitch = pitch8 / sizeof(float); | |
| 442 | ✗ | float center_weight = amount; | |
| 443 | ✗ | float outer_weight = (1.0f - amount) / 2.0f; | |
| 444 | float left; | ||
| 445 | ✗ | for (size_t y = height; y>0; --y) { | |
| 446 | ✗ | left = dstp[0]; | |
| 447 | af_horizontal_planar_process_line_float_c(left, dstp, row_size, center_weight, outer_weight); | ||
| 448 | ✗ | dstp += pitch; | |
| 449 | } | ||
| 450 | ✗ | } | |
| 451 | |||
| 452 | ✗ | static void copy_frame(const PVideoFrame &src, PVideoFrame &dst, IScriptEnvironment *env, const int *planes, int plane_count) { | |
| 453 | ✗ | for (int p = 0; p < plane_count; p++) { | |
| 454 | ✗ | int plane = planes[p]; | |
| 455 | ✗ | env->BitBlt(dst->GetWritePtr(plane), dst->GetPitch(plane), src->GetReadPtr(plane), | |
| 456 | src->GetPitch(plane), src->GetRowSize(plane), src->GetHeight(plane)); | ||
| 457 | } | ||
| 458 | ✗ | } | |
| 459 | |||
| 460 | // ---------------------------------- | ||
| 461 | // Blur/Sharpen Horizontal GetFrame() | ||
| 462 | // ---------------------------------- | ||
| 463 | |||
| 464 | ✗ | PVideoFrame __stdcall AdjustFocusH::GetFrame(int n, IScriptEnvironment* env) | |
| 465 | { | ||
| 466 | ✗ | PVideoFrame src = child->GetFrame(n, env); | |
| 467 | ✗ | PVideoFrame dst = env->NewVideoFrameP(vi, &src); | |
| 468 | |||
| 469 | ✗ | const int planesYUV[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A}; | |
| 470 | ✗ | const int planesRGB[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A}; | |
| 471 | ✗ | const int *planes = vi.IsYUV() || vi.IsYUVA() ? planesYUV : planesRGB; | |
| 472 | |||
| 473 | ✗ | int pixelsize = vi.ComponentSize(); | |
| 474 | |||
| 475 | ✗ | if (vi.IsPlanar()) { | |
| 476 | ✗ | copy_frame(src, dst, env, planes, vi.NumComponents() ); //planar processing is always in-place | |
| 477 | ✗ | int bits_per_pixel = vi.BitsPerComponent(); | |
| 478 | ✗ | for(int cplane=0;cplane<3;cplane++) { | |
| 479 | ✗ | int plane = planes[cplane]; | |
| 480 | ✗ | int row_size = dst->GetRowSize(plane); | |
| 481 | ✗ | BYTE* q = dst->GetWritePtr(plane); | |
| 482 | ✗ | int pitch = dst->GetPitch(plane); | |
| 483 | ✗ | int height = dst->GetHeight(plane); | |
| 484 | #ifdef INTEL_INTRINSICS | ||
| 485 | ✗ | if (pixelsize == 1 && (env->GetCPUFlags() & CPUF_AVX2) && row_size > 32) { | |
| 486 | ✗ | af_horizontal_planar_avx2(q, height, pitch, row_size, half_amount); | |
| 487 | } | ||
| 488 | else | ||
| 489 | ✗ | if (pixelsize==1 && (env->GetCPUFlags() & CPUF_SSE2) && row_size > 16) { | |
| 490 | ✗ | af_horizontal_planar_sse2(q, height, pitch, row_size, half_amount); | |
| 491 | } else | ||
| 492 | #ifdef X86_32 | ||
| 493 | if (pixelsize == 1 && (env->GetCPUFlags() & CPUF_MMX) && row_size > 8) { | ||
| 494 | af_horizontal_planar_mmx(q,height,pitch,row_size,half_amount); | ||
| 495 | } else | ||
| 496 | #endif | ||
| 497 | ✗ | if (pixelsize == 2 && (env->GetCPUFlags() & CPUF_AVX2) && row_size > 32) { | |
| 498 | ✗ | af_horizontal_planar_uint16_t_avx2(q, height, pitch, row_size, half_amount, bits_per_pixel); | |
| 499 | } | ||
| 500 | ✗ | else if (pixelsize == 2 && (env->GetCPUFlags() & CPUF_SSE4_1) && row_size > 16) { | |
| 501 | ✗ | af_horizontal_planar_uint16_t_sse41(q, height, pitch, row_size, half_amount, bits_per_pixel); | |
| 502 | } | ||
| 503 | ✗ | else if (pixelsize == 2 && (env->GetCPUFlags() & CPUF_SSE2) && row_size > 16) { | |
| 504 | ✗ | af_horizontal_planar_uint16_t_sse2(q, height, pitch, row_size, half_amount, bits_per_pixel); | |
| 505 | } | ||
| 506 | ✗ | else if (pixelsize == 4 && (env->GetCPUFlags() & CPUF_SSE2) && row_size > 16) { | |
| 507 | ✗ | af_horizontal_planar_float_sse2(q, height, pitch, row_size, (float)amountd); | |
| 508 | } | ||
| 509 | else | ||
| 510 | #endif | ||
| 511 | { | ||
| 512 | ✗ | switch (pixelsize) { | |
| 513 | ✗ | case 1: af_horizontal_planar_c<uint8_t>(q, height, pitch, row_size, half_amount, bits_per_pixel); break; | |
| 514 | ✗ | case 2: af_horizontal_planar_c<uint16_t>(q, height, pitch, row_size, half_amount, bits_per_pixel); break; | |
| 515 | ✗ | default: // 4: float | |
| 516 | ✗ | af_horizontal_planar_float_c(q, height, pitch, row_size, (float)amountd); break; | |
| 517 | } | ||
| 518 | } | ||
| 519 | } | ||
| 520 | } else { | ||
| 521 | ✗ | if (vi.IsYUY2()) { | |
| 522 | ✗ | BYTE* q = dst->GetWritePtr(); | |
| 523 | ✗ | const int pitch = dst->GetPitch(); | |
| 524 | #ifdef INTEL_INTRINSICS | ||
| 525 | ✗ | if ((env->GetCPUFlags() & CPUF_SSE2) && vi.width>8) { | |
| 526 | ✗ | af_horizontal_yuy2_sse2(dst->GetWritePtr(), src->GetReadPtr(), dst->GetPitch(), src->GetPitch(), vi.height, vi.width, half_amount); | |
| 527 | } else | ||
| 528 | #ifdef X86_32 | ||
| 529 | if ((env->GetCPUFlags() & CPUF_MMX) && vi.width>8) { | ||
| 530 | af_horizontal_yuy2_mmx(dst->GetWritePtr(), src->GetReadPtr(), dst->GetPitch(), src->GetPitch(), vi.height, vi.width, half_amount); | ||
| 531 | } else | ||
| 532 | #endif | ||
| 533 | #endif | ||
| 534 | { | ||
| 535 | ✗ | copy_frame(src, dst, env, planesYUV, 1); //in-place | |
| 536 | ✗ | af_horizontal_yuy2_c(q,vi.height,pitch,vi.width,half_amount); | |
| 537 | } | ||
| 538 | } | ||
| 539 | ✗ | else if (vi.IsRGB32() || vi.IsRGB64()) { | |
| 540 | #ifdef INTEL_INTRINSICS | ||
| 541 | ✗ | if ((pixelsize==1) && (env->GetCPUFlags() & CPUF_SSE2) && vi.width>4) { | |
| 542 | //this one is NOT in-place | ||
| 543 | ✗ | af_horizontal_rgb32_sse2(dst->GetWritePtr(), src->GetReadPtr(), dst->GetPitch(), src->GetPitch(), vi.height, vi.width, half_amount); | |
| 544 | } | ||
| 545 | ✗ | else if ((pixelsize == 2) && (env->GetCPUFlags() & CPUF_SSE4_1) && vi.width > 2) { | |
| 546 | //this one is NOT in-place | ||
| 547 | ✗ | af_horizontal_rgb64_sse41(dst->GetWritePtr(), src->GetReadPtr(), dst->GetPitch(), src->GetPitch(), vi.height, vi.width, half_amount); // really width | |
| 548 | } | ||
| 549 | ✗ | else if ((pixelsize == 2) && (env->GetCPUFlags() & CPUF_SSE2) && vi.width > 2) { | |
| 550 | //this one is NOT in-place | ||
| 551 | ✗ | af_horizontal_rgb64_sse2(dst->GetWritePtr(), src->GetReadPtr(), dst->GetPitch(), src->GetPitch(), vi.height, vi.width, half_amount); // really width | |
| 552 | } | ||
| 553 | else | ||
| 554 | #ifdef X86_32 | ||
| 555 | if ((pixelsize==1) && (env->GetCPUFlags() & CPUF_MMX) && vi.width > 2) | ||
| 556 | { //so as this one | ||
| 557 | af_horizontal_rgb32_mmx(dst->GetWritePtr(), src->GetReadPtr(), dst->GetPitch(), src->GetPitch(), vi.height, vi.width, half_amount); | ||
| 558 | } else | ||
| 559 | #endif | ||
| 560 | #endif | ||
| 561 | { | ||
| 562 | ✗ | copy_frame(src, dst, env, planesYUV, 1); | |
| 563 | ✗ | if(pixelsize==1) | |
| 564 | ✗ | af_horizontal_rgb32_64_c<uint8_t>(dst->GetWritePtr(), vi.height, dst->GetPitch(), vi.width, half_amount); | |
| 565 | else | ||
| 566 | ✗ | af_horizontal_rgb32_64_c<uint16_t>(dst->GetWritePtr(), vi.height, dst->GetPitch(), vi.width, half_amount); | |
| 567 | } | ||
| 568 | ✗ | } else if (vi.IsRGB24() || vi.IsRGB48()) { | |
| 569 | ✗ | copy_frame(src, dst, env, planesYUV, 1); | |
| 570 | ✗ | if(pixelsize==1) | |
| 571 | ✗ | af_horizontal_rgb24_48_c<uint8_t>(dst->GetWritePtr(), vi.height, dst->GetPitch(), vi.width, half_amount); | |
| 572 | else | ||
| 573 | ✗ | af_horizontal_rgb24_48_c<uint16_t>(dst->GetWritePtr(), vi.height, dst->GetPitch(), vi.width, half_amount); | |
| 574 | } | ||
| 575 | } | ||
| 576 | |||
| 577 | ✗ | return dst; | |
| 578 | ✗ | } | |
| 579 | |||
| 580 | |||
| 581 | /************************************************ | ||
| 582 | ******* Sharpen/Blur Factory Methods ******* | ||
| 583 | ***********************************************/ | ||
| 584 | |||
| 585 | ✗ | AVSValue __cdecl Create_Sharpen(AVSValue args, void*, IScriptEnvironment* env) | |
| 586 | { | ||
| 587 | ✗ | const double amountH = args[1].AsFloat(), amountV = args[2].AsDblDef(amountH); | |
| 588 | |||
| 589 | ✗ | if (amountH < -1.5849625 || amountH > 1.0 || amountV < -1.5849625 || amountV > 1.0) // log2(3) | |
| 590 | ✗ | env->ThrowError("Sharpen: arguments must be in the range -1.58 to 1.0"); | |
| 591 | |||
| 592 | ✗ | if (fabs(amountH) < 0.00002201361136) { // log2(1+1/65536) | |
| 593 | ✗ | if (fabs(amountV) < 0.00002201361136) { | |
| 594 | ✗ | return args[0].AsClip(); | |
| 595 | } | ||
| 596 | else { | ||
| 597 | ✗ | return new AdjustFocusV(amountV, args[0].AsClip()); | |
| 598 | } | ||
| 599 | } | ||
| 600 | else { | ||
| 601 | ✗ | if (fabs(amountV) < 0.00002201361136) { | |
| 602 | ✗ | return new AdjustFocusH(amountH, args[0].AsClip()); | |
| 603 | } | ||
| 604 | else { | ||
| 605 | ✗ | return new AdjustFocusH(amountH, new AdjustFocusV(amountV, args[0].AsClip())); | |
| 606 | } | ||
| 607 | } | ||
| 608 | } | ||
| 609 | |||
| 610 | ✗ | AVSValue __cdecl Create_Blur(AVSValue args, void*, IScriptEnvironment* env) | |
| 611 | { | ||
| 612 | ✗ | const double amountH = args[1].AsFloat(), amountV = args[2].AsDblDef(amountH); | |
| 613 | |||
| 614 | ✗ | if (amountH < -1.0 || amountH > 1.5849625 || amountV < -1.0 || amountV > 1.5849625) // log2(3) | |
| 615 | ✗ | env->ThrowError("Blur: arguments must be in the range -1.0 to 1.58"); | |
| 616 | |||
| 617 | ✗ | if (fabs(amountH) < 0.00002201361136) { // log2(1+1/65536) | |
| 618 | ✗ | if (fabs(amountV) < 0.00002201361136) { | |
| 619 | ✗ | return args[0].AsClip(); | |
| 620 | } | ||
| 621 | else { | ||
| 622 | ✗ | return new AdjustFocusV(-amountV, args[0].AsClip()); | |
| 623 | } | ||
| 624 | } | ||
| 625 | else { | ||
| 626 | ✗ | if (fabs(amountV) < 0.00002201361136) { | |
| 627 | ✗ | return new AdjustFocusH(-amountH, args[0].AsClip()); | |
| 628 | } | ||
| 629 | else { | ||
| 630 | ✗ | return new AdjustFocusH(-amountH, new AdjustFocusV(-amountV, args[0].AsClip())); | |
| 631 | } | ||
| 632 | } | ||
| 633 | } | ||
| 634 | |||
| 635 | |||
| 636 | |||
| 637 | |||
| 638 | /*************************** | ||
| 639 | **** TemporalSoften ***** | ||
| 640 | **************************/ | ||
| 641 | |||
| 642 | 4 | TemporalSoften::TemporalSoften( PClip _child, unsigned radius, unsigned luma_thresh, | |
| 643 | 4 | unsigned chroma_thresh, int _scenechange, IScriptEnvironment* env ) | |
| 644 | : GenericVideoFilter(_child), | ||
| 645 | 4 | scenechange(_scenechange), | |
| 646 | 8 | luma_threshold(min(luma_thresh, 255u)), | |
| 647 | 4 | chroma_threshold(min(chroma_thresh, 255u)), | |
| 648 |
2/4✓ Branch 2 → 3 taken 4 times.
✗ Branch 2 → 77 not taken.
✓ Branch 3 → 4 taken 4 times.
✗ Branch 3 → 75 not taken.
|
8 | kernel(2 * min(radius, (unsigned int)MAX_RADIUS) + 1) |
| 649 | { | ||
| 650 | |||
| 651 |
1/2✓ Branch 9 → 10 taken 4 times.
✗ Branch 9 → 78 not taken.
|
4 | child->SetCacheHints(CACHE_WINDOW,kernel); |
| 652 | |||
| 653 |
5/10✓ Branch 10 → 11 taken 4 times.
✗ Branch 10 → 78 not taken.
✓ Branch 11 → 12 taken 4 times.
✗ Branch 11 → 14 not taken.
✓ Branch 12 → 13 taken 4 times.
✗ Branch 12 → 78 not taken.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 4 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 4 times.
|
4 | if (vi.IsRGB24() || vi.IsRGB48()) { |
| 654 | ✗ | env->ThrowError("TemporalSoften: RGB24/48 Not supported, use ConvertToRGB32/48()."); | |
| 655 | } | ||
| 656 | |||
| 657 |
5/12✓ Branch 18 → 19 taken 4 times.
✗ Branch 18 → 78 not taken.
✓ Branch 19 → 20 taken 4 times.
✗ Branch 19 → 22 not taken.
✓ Branch 20 → 21 taken 4 times.
✗ Branch 20 → 78 not taken.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 24 taken 4 times.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 24 not taken.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 4 times.
|
4 | if ((vi.IsRGB32() || vi.IsRGB64()) && (vi.width&1)) { |
| 658 | ✗ | env->ThrowError("TemporalSoften: RGB32/64 source must be multiple of 2 in width."); | |
| 659 | } | ||
| 660 | |||
| 661 |
3/8✓ Branch 27 → 28 taken 4 times.
✗ Branch 27 → 78 not taken.
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 31 taken 4 times.
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 31 not taken.
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 34 taken 4 times.
|
4 | if ((vi.IsYUY2()) && (vi.width&3)) { |
| 662 | ✗ | env->ThrowError("TemporalSoften: YUY2 source must be multiple of 4 in width."); | |
| 663 | } | ||
| 664 | |||
| 665 |
1/2✗ Branch 34 → 35 not taken.
✓ Branch 34 → 36 taken 4 times.
|
4 | if (scenechange >= 255) { |
| 666 | ✗ | scenechange = 0; | |
| 667 | } | ||
| 668 | |||
| 669 |
2/12✗ Branch 36 → 37 not taken.
✓ Branch 36 → 42 taken 4 times.
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 78 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 41 not taken.
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 78 not taken.
✗ Branch 40 → 41 not taken.
✗ Branch 40 → 42 not taken.
✗ Branch 43 → 44 not taken.
✓ Branch 43 → 45 taken 4 times.
|
4 | if (scenechange>0 && (vi.IsRGB32() || vi.IsRGB64())) { |
| 670 | ✗ | env->ThrowError("TemporalSoften: Scenechange not available on RGB32/64"); | |
| 671 | } | ||
| 672 | |||
| 673 |
1/2✓ Branch 45 → 46 taken 4 times.
✗ Branch 45 → 78 not taken.
|
4 | pixelsize = vi.ComponentSize(); |
| 674 |
1/2✓ Branch 46 → 47 taken 4 times.
✗ Branch 46 → 78 not taken.
|
4 | bits_per_pixel = vi.BitsPerComponent(); |
| 675 | |||
| 676 | // original scenechange parameter always 0-255 | ||
| 677 | int factor; | ||
| 678 |
2/4✓ Branch 47 → 48 taken 4 times.
✗ Branch 47 → 78 not taken.
✓ Branch 48 → 49 taken 4 times.
✗ Branch 48 → 50 not taken.
|
4 | if (vi.IsPlanar()) // Y/YUV, no Planar RGB here |
| 679 | 4 | factor = 1; // bitdepth independent. sad normalizes | |
| 680 | else | ||
| 681 | ✗ | factor = vi.BytesFromPixels(1) / pixelsize; // /pixelsize: correction for packed 16 bit rgb | |
| 682 | 4 | scenechange *= ((vi.width/32)*32)*vi.height*factor; // why /*32? | |
| 683 | |||
| 684 | |||
| 685 | 4 | int c = 0; | |
| 686 |
5/14✓ Branch 52 → 53 taken 4 times.
✗ Branch 52 → 78 not taken.
✓ Branch 53 → 54 taken 4 times.
✗ Branch 53 → 59 not taken.
✓ Branch 54 → 55 taken 4 times.
✗ Branch 54 → 78 not taken.
✗ Branch 55 → 56 not taken.
✓ Branch 55 → 58 taken 4 times.
✗ Branch 56 → 57 not taken.
✗ Branch 56 → 78 not taken.
✗ Branch 57 → 58 not taken.
✗ Branch 57 → 59 not taken.
✓ Branch 60 → 61 taken 4 times.
✗ Branch 60 → 65 not taken.
|
4 | if (vi.IsPlanar() && (vi.IsYUV() || vi.IsYUVA())) { |
| 687 |
1/2✓ Branch 61 → 62 taken 4 times.
✗ Branch 61 → 63 not taken.
|
4 | if (luma_thresh>0) { |
| 688 | 4 | planes[c].planeId = PLANAR_Y; | |
| 689 | 4 | planes[c++].threshold = luma_thresh; | |
| 690 | } | ||
| 691 |
2/2✓ Branch 63 → 64 taken 3 times.
✓ Branch 63 → 74 taken 1 time.
|
4 | if (chroma_thresh>0) { |
| 692 | 3 | planes[c].planeId = PLANAR_V; | |
| 693 | 3 | planes[c++].threshold =chroma_thresh; | |
| 694 | 3 | planes[c].planeId = PLANAR_U; | |
| 695 | 3 | planes[c++].threshold = chroma_thresh; | |
| 696 | } | ||
| 697 | ✗ | } else if (vi.IsYUY2()) { | |
| 698 | ✗ | planes[c].planeId=0; | |
| 699 | ✗ | planes[c++].threshold=luma_thresh|(chroma_thresh<<8); | |
| 700 | ✗ | } else if (vi.IsRGB()) { // For RGB We use Luma. | |
| 701 | ✗ | if (vi.IsPlanar()) { | |
| 702 | ✗ | planes[c].planeId = PLANAR_G; | |
| 703 | ✗ | planes[c++].threshold = luma_thresh; | |
| 704 | ✗ | planes[c].planeId = PLANAR_B; | |
| 705 | ✗ | planes[c++].threshold = luma_thresh; | |
| 706 | ✗ | planes[c].planeId = PLANAR_R; | |
| 707 | ✗ | planes[c++].threshold = luma_thresh; | |
| 708 | } | ||
| 709 | else { // packed RGB | ||
| 710 | ✗ | planes[c].planeId = 0; | |
| 711 | ✗ | planes[c++].threshold = luma_thresh; | |
| 712 | } | ||
| 713 | } | ||
| 714 | 4 | planes[c].planeId=0; | |
| 715 | 4 | } | |
| 716 | |||
| 717 | //offset is the initial value of x. Used when C routine processes only parts of frames after SSE/MMX paths do their job. | ||
| 718 | template<typename pixel_t, bool maxThreshold> | ||
| 719 | 9 | static void accumulate_line_c(BYTE* _c_plane, const BYTE** planeP, int planes, int offset, size_t rowsize, BYTE _threshold, int div, int bits_per_pixel) { | |
| 720 | 9 | pixel_t *c_plane = reinterpret_cast<pixel_t *>(_c_plane); | |
| 721 | |||
| 722 | typedef typename std::conditional < sizeof(pixel_t) <= 2, int, float>::type sum_t; | ||
| 723 | typedef typename std::conditional < sizeof(pixel_t) == 1, int, int64_t>::type bigsum_t; | ||
| 724 | typedef typename std::conditional < std::is_floating_point<pixel_t>::value, float, int>::type threshold_t; | ||
| 725 | |||
| 726 | 9 | size_t width = rowsize / sizeof(pixel_t); | |
| 727 | |||
| 728 | 9 | threshold_t threshold = _threshold; // parameter 0..255 | |
| 729 | if (std::is_floating_point<pixel_t>::value) | ||
| 730 | 9 | threshold = (threshold_t)(threshold / 255.0f); // float | |
| 731 | else if constexpr(sizeof(pixel_t) == 2) { | ||
| 732 | ✗ | threshold = threshold * (uint16_t)(1 << (bits_per_pixel - 8)); // uint16_t, 10 bit: *4 16bit: *256 | |
| 733 | } | ||
| 734 | |||
| 735 |
2/12void accumulate_line_c<float, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✓ Branch 15 → 5 taken 144 times.
✓ Branch 15 → 16 taken 9 times.
void accumulate_line_c<float, true>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 12 → 5 not taken.
✗ Branch 12 → 13 not taken.
void accumulate_line_c<unsigned char, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 12 → 4 not taken.
✗ Branch 12 → 13 not taken.
void accumulate_line_c<unsigned char, true>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 10 → 4 not taken.
✗ Branch 10 → 11 not taken.
void accumulate_line_c<unsigned short, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 12 → 4 not taken.
✗ Branch 12 → 13 not taken.
void accumulate_line_c<unsigned short, true>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 10 → 4 not taken.
✗ Branch 10 → 11 not taken.
|
153 | for (size_t x = offset; x < width; ++x) { |
| 736 | 144 | pixel_t current = c_plane[x]; | |
| 737 | 144 | sum_t sum = current; | |
| 738 | |||
| 739 |
2/12void accumulate_line_c<float, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✓ Branch 12 → 6 taken 288 times.
✓ Branch 12 → 13 taken 144 times.
void accumulate_line_c<float, true>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void accumulate_line_c<unsigned char, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 10 → 5 not taken.
✗ Branch 10 → 11 not taken.
void accumulate_line_c<unsigned char, true>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 8 → 5 not taken.
✗ Branch 8 → 9 not taken.
void accumulate_line_c<unsigned short, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 10 → 5 not taken.
✗ Branch 10 → 11 not taken.
void accumulate_line_c<unsigned short, true>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 8 → 5 not taken.
✗ Branch 8 → 9 not taken.
|
432 | for (int plane = planes - 1; plane >= 0; plane--) { |
| 740 | 288 | pixel_t p = reinterpret_cast<const pixel_t *>(planeP[plane])[x]; | |
| 741 | if (maxThreshold) { | ||
| 742 | ✗ | sum += p; // simple frame average mode | |
| 743 | } | ||
| 744 | else { | ||
| 745 | 288 | sum_t absdiff = std::abs(current - p); | |
| 746 | |||
| 747 |
2/6void accumulate_line_c<float, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✓ Branch 8 → 9 taken 151 times.
✓ Branch 8 → 10 taken 137 times.
void accumulate_line_c<unsigned char, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
void accumulate_line_c<unsigned short, false>(unsigned char*, unsigned char const**, int, int, unsigned long, unsigned char, int, int):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
|
288 | if (absdiff <= threshold) { |
| 748 | 151 | sum += p; | |
| 749 | } | ||
| 750 | else { | ||
| 751 | 137 | sum += current; | |
| 752 | } | ||
| 753 | } | ||
| 754 | } | ||
| 755 | if (std::is_floating_point<pixel_t>::value) | ||
| 756 | 144 | c_plane[x] = (pixel_t)(sum / (planes + 1)); // float: simple average | |
| 757 | else | ||
| 758 | ✗ | c_plane[x] = (pixel_t)(((bigsum_t)sum * div + 16384) >> 15); // div = 32768/(planes+1) for integer arithmetic | |
| 759 | } | ||
| 760 | 9 | } | |
| 761 | |||
| 762 | ✗ | static void accumulate_line_yuy2_c(BYTE* c_plane, const BYTE** planeP, int planes, size_t width, BYTE threshold_luma, BYTE threshold_chroma, int div) { | |
| 763 | ✗ | for (size_t x = 0; x < width; x+=2) { | |
| 764 | ✗ | BYTE current_y = c_plane[x]; | |
| 765 | ✗ | BYTE current_c = c_plane[x+1]; | |
| 766 | ✗ | size_t sum_y = current_y; | |
| 767 | ✗ | size_t sum_c = current_c; | |
| 768 | |||
| 769 | ✗ | for (int plane = planes - 1; plane >= 0; plane--) { | |
| 770 | ✗ | BYTE p_y = planeP[plane][x]; | |
| 771 | ✗ | BYTE p_c = planeP[plane][x+1]; | |
| 772 | ✗ | size_t absdiff_y = std::abs(current_y - p_y); | |
| 773 | ✗ | size_t absdiff_c = std::abs(current_c - p_c); | |
| 774 | |||
| 775 | ✗ | if (absdiff_y <= threshold_luma) { | |
| 776 | ✗ | sum_y += p_y; | |
| 777 | } else { | ||
| 778 | ✗ | sum_y += current_y; | |
| 779 | } | ||
| 780 | |||
| 781 | ✗ | if (absdiff_c <= threshold_chroma) { | |
| 782 | ✗ | sum_c += p_c; | |
| 783 | } else { | ||
| 784 | ✗ | sum_c += current_c; | |
| 785 | } | ||
| 786 | } | ||
| 787 | |||
| 788 | ✗ | c_plane[x] = (BYTE)((sum_y * div + 16384) >> 15); | |
| 789 | ✗ | c_plane[x+1] = (BYTE)((sum_c * div + 16384) >> 15); | |
| 790 | } | ||
| 791 | ✗ | } | |
| 792 | |||
| 793 | ✗ | static void accumulate_line_yuy2(BYTE* c_plane, const BYTE** planeP, int planes, size_t width, BYTE threshold_luma, BYTE threshold_chroma, int div, IScriptEnvironment* env) | |
| 794 | { | ||
| 795 | #ifdef INTEL_INTRINSICS | ||
| 796 | ✗ | if ((env->GetCPUFlags() & CPUF_SSE2) && width >= 16) { | |
| 797 | ✗ | accumulate_line_sse2<false>(c_plane, planeP, planes, width, threshold_luma | (threshold_chroma << 8), div); | |
| 798 | } else | ||
| 799 | #ifdef X86_32 | ||
| 800 | if ((env->GetCPUFlags() & CPUF_MMX) && width >= 8) { | ||
| 801 | accumulate_line_mmx(c_plane, planeP, planes, width, threshold_luma | (threshold_chroma << 8), div); //yuy2 is always at least mod8 | ||
| 802 | } else | ||
| 803 | #endif | ||
| 804 | #endif | ||
| 805 | ✗ | accumulate_line_yuy2_c(c_plane, planeP, planes, width, threshold_luma, threshold_chroma, div); | |
| 806 | ✗ | } | |
| 807 | |||
| 808 | 35 | static void accumulate_line(BYTE* c_plane, const BYTE** planeP, int planes, size_t rowsize, BYTE threshold, int div, int pixelsize, int bits_per_pixel, IScriptEnvironment* env) { | |
| 809 | // threshold == 255: simple average | ||
| 810 | 35 | bool maxThreshold = (threshold == 255); | |
| 811 | #ifdef INTEL_INTRINSICS | ||
| 812 |
6/8✓ Branch 2 → 3 taken 15 times.
✓ Branch 2 → 7 taken 20 times.
✓ Branch 4 → 5 taken 15 times.
✗ Branch 4 → 7 not taken.
✓ Branch 5 → 6 taken 15 times.
✗ Branch 5 → 7 not taken.
✓ Branch 8 → 9 taken 15 times.
✓ Branch 8 → 16 taken 20 times.
|
35 | if ((pixelsize == 2) && (env->GetCPUFlags() & CPUF_SSE4) && rowsize >= 16) { |
| 813 | // <maxThreshold, lessThan16bit> | ||
| 814 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 13 taken 15 times.
|
15 | if(maxThreshold) { |
| 815 | ✗ | if(bits_per_pixel < 16) | |
| 816 | ✗ | accumulate_line_16_sse41<true, true>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel); | |
| 817 | else | ||
| 818 | ✗ | accumulate_line_16_sse41<true, false>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel); | |
| 819 | } | ||
| 820 | else { | ||
| 821 |
1/2✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 15 times.
|
15 | if (bits_per_pixel < 16) |
| 822 | ✗ | accumulate_line_16_sse41<false, true>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel); | |
| 823 | else | ||
| 824 | 15 | accumulate_line_16_sse41<false, false>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel); | |
| 825 | } | ||
| 826 |
2/8✗ Branch 16 → 17 not taken.
✓ Branch 16 → 21 taken 20 times.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 21 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 30 taken 20 times.
|
20 | } else if ((pixelsize == 2) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) { |
| 827 | // <maxThreshold, lessThan16bit> | ||
| 828 | ✗ | if(maxThreshold) { | |
| 829 | ✗ | if(bits_per_pixel < 16) | |
| 830 | ✗ | accumulate_line_16_sse2<true, true>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel); | |
| 831 | else | ||
| 832 | ✗ | accumulate_line_16_sse2<true, false>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel); | |
| 833 | } | ||
| 834 | else { | ||
| 835 | ✗ | if (bits_per_pixel < 16) | |
| 836 | ✗ | accumulate_line_16_sse2<false, true>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel); | |
| 837 | else | ||
| 838 | ✗ | accumulate_line_16_sse2<false, false>(c_plane, planeP, planes, rowsize, threshold << (bits_per_pixel - 8), div, bits_per_pixel); | |
| 839 | } | ||
| 840 | } | ||
| 841 |
6/8✓ Branch 30 → 31 taken 11 times.
✓ Branch 30 → 35 taken 9 times.
✓ Branch 32 → 33 taken 11 times.
✗ Branch 32 → 35 not taken.
✓ Branch 33 → 34 taken 11 times.
✗ Branch 33 → 35 not taken.
✓ Branch 36 → 37 taken 11 times.
✓ Branch 36 → 40 taken 9 times.
|
20 | else if ((pixelsize == 1) && (env->GetCPUFlags() & CPUF_SSSE3) && rowsize >= 16) { |
| 842 |
1/2✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 11 times.
|
11 | if (maxThreshold) // <maxThreshold |
| 843 | ✗ | accumulate_line_ssse3<true>(c_plane, planeP, planes, rowsize, threshold | (threshold << 8), div); | |
| 844 | else | ||
| 845 | 11 | accumulate_line_ssse3<false>(c_plane, planeP, planes, rowsize, threshold | (threshold << 8), div); | |
| 846 |
2/8✗ Branch 40 → 41 not taken.
✓ Branch 40 → 45 taken 9 times.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 45 not taken.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 45 not taken.
✗ Branch 46 → 47 not taken.
✓ Branch 46 → 50 taken 9 times.
|
9 | } else if ((pixelsize == 1) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) { |
| 847 | ✗ | if (maxThreshold) | |
| 848 | ✗ | accumulate_line_sse2<true>(c_plane, planeP, planes, rowsize, threshold | (threshold << 8), div); | |
| 849 | else | ||
| 850 | ✗ | accumulate_line_sse2<false>(c_plane, planeP, planes, rowsize, threshold | (threshold << 8), div); | |
| 851 | } | ||
| 852 | else | ||
| 853 | #ifdef X86_32 | ||
| 854 | if ((pixelsize == 1) && (env->GetCPUFlags() & CPUF_MMX) && rowsize >= 8) { | ||
| 855 | size_t mod8_width = rowsize / 8 * 8; | ||
| 856 | accumulate_line_mmx(c_plane, planeP, planes, rowsize, threshold | (threshold << 8), div); | ||
| 857 | |||
| 858 | if (mod8_width != rowsize) { | ||
| 859 | accumulate_line_c<uint8_t, false>(c_plane, planeP, planes, mod8_width, rowsize - mod8_width, threshold, div, bits_per_pixel); | ||
| 860 | } | ||
| 861 | } else | ||
| 862 | #endif | ||
| 863 | #endif | ||
| 864 | |||
| 865 | { | ||
| 866 |
1/4✗ Branch 50 → 51 not taken.
✗ Branch 50 → 55 not taken.
✓ Branch 50 → 59 taken 9 times.
✗ Branch 50 → 63 not taken.
|
9 | switch(pixelsize) { |
| 867 | ✗ | case 1: | |
| 868 | ✗ | if (maxThreshold) | |
| 869 | ✗ | accumulate_line_c<uint8_t, true>(c_plane, planeP, planes, 0, rowsize, threshold, div, bits_per_pixel); | |
| 870 | else | ||
| 871 | ✗ | accumulate_line_c<uint8_t, false>(c_plane, planeP, planes, 0, rowsize, threshold, div, bits_per_pixel); | |
| 872 | ✗ | break; | |
| 873 | ✗ | case 2: | |
| 874 | ✗ | if (maxThreshold) | |
| 875 | ✗ | accumulate_line_c<uint16_t, true>(c_plane, planeP, planes, 0, rowsize, threshold, div, bits_per_pixel); | |
| 876 | else | ||
| 877 | ✗ | accumulate_line_c<uint16_t, false>(c_plane, planeP, planes, 0, rowsize, threshold, div, bits_per_pixel); | |
| 878 | ✗ | break; | |
| 879 | 9 | case 4: | |
| 880 |
1/2✗ Branch 59 → 60 not taken.
✓ Branch 59 → 61 taken 9 times.
|
9 | if (maxThreshold) |
| 881 | ✗ | accumulate_line_c<float, true>(c_plane, planeP, planes, 0, rowsize, threshold, div, bits_per_pixel); | |
| 882 | else | ||
| 883 | 9 | accumulate_line_c<float, false>(c_plane, planeP, planes, 0, rowsize, threshold, div, bits_per_pixel); | |
| 884 | 9 | break; | |
| 885 | } | ||
| 886 | } | ||
| 887 | 35 | } | |
| 888 | |||
| 889 | template<typename pixel_t> | ||
| 890 | ✗ | static int64_t calculate_sad_c(const BYTE* cur_ptr, const BYTE* other_ptr, int cur_pitch, int other_pitch, size_t rowsize, size_t height) | |
| 891 | { | ||
| 892 | ✗ | const pixel_t *ptr1 = reinterpret_cast<const pixel_t *>(cur_ptr); | |
| 893 | ✗ | const pixel_t *ptr2 = reinterpret_cast<const pixel_t *>(other_ptr); | |
| 894 | ✗ | size_t width = rowsize / sizeof(pixel_t); | |
| 895 | ✗ | cur_pitch /= sizeof(pixel_t); | |
| 896 | ✗ | other_pitch /= sizeof(pixel_t); | |
| 897 | |||
| 898 | // for fullframe float may loose precision | ||
| 899 | typedef typename std::conditional < std::is_floating_point<pixel_t>::value, double, int64_t>::type sum_t; | ||
| 900 | // for one row int is enough and faster than int64 | ||
| 901 | typedef typename std::conditional < std::is_floating_point<pixel_t>::value, float, int>::type sumrow_t; | ||
| 902 | ✗ | sum_t sum = 0; | |
| 903 | |||
| 904 | ✗ | for (size_t y = 0; y < height; ++y) { | |
| 905 | ✗ | sumrow_t sumrow = 0; | |
| 906 | ✗ | for (size_t x = 0; x < width; ++x) { | |
| 907 | ✗ | sumrow += std::abs(ptr1[x] - ptr2[x]); | |
| 908 | } | ||
| 909 | ✗ | sum += sumrow; | |
| 910 | ✗ | ptr1 += cur_pitch; | |
| 911 | ✗ | ptr2 += other_pitch; | |
| 912 | } | ||
| 913 | if (std::is_floating_point<pixel_t>::value) | ||
| 914 | ✗ | return (int64_t)(sum * 255); // scale 0..1 based sum to 8 bit range | |
| 915 | else | ||
| 916 | ✗ | return (int64_t)sum; // for int, scaling to 8 bit range is done outside | |
| 917 | } | ||
| 918 | |||
| 919 | // sum of byte-diffs. | ||
| 920 | ✗ | static int64_t calculate_sad(const BYTE* cur_ptr, const BYTE* other_ptr, int cur_pitch, int other_pitch, size_t rowsize, size_t height, int pixelsize, int bits_per_pixel, IScriptEnvironment* env) { | |
| 921 | #ifdef INTEL_INTRINSICS | ||
| 922 | // todo: sse for float | ||
| 923 | ✗ | if ((pixelsize == 1) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) { | |
| 924 | ✗ | return (int64_t)calculate_sad_sse2<false>(cur_ptr, other_ptr, cur_pitch, other_pitch, rowsize, height); | |
| 925 | } | ||
| 926 | #ifdef X86_32 | ||
| 927 | if ((pixelsize ==1 ) && (env->GetCPUFlags() & CPUF_INTEGER_SSE) && rowsize >= 8) { | ||
| 928 | return (int64_t)calculate_sad_isse(cur_ptr, other_ptr, cur_pitch, other_pitch, rowsize, height); | ||
| 929 | } | ||
| 930 | #endif | ||
| 931 | // sse2 uint16_t | ||
| 932 | ✗ | if ((pixelsize == 2) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) { | |
| 933 | ✗ | return calculate_sad_8_or_16_sse2<uint16_t, false>(cur_ptr, other_ptr, cur_pitch, other_pitch, rowsize, height) >> (bits_per_pixel-8); | |
| 934 | } | ||
| 935 | #endif | ||
| 936 | |||
| 937 | ✗ | switch(pixelsize) { | |
| 938 | ✗ | case 1: return calculate_sad_c<uint8_t>(cur_ptr, other_ptr, cur_pitch, other_pitch, rowsize, height); | |
| 939 | ✗ | case 2: return calculate_sad_c<uint16_t>(cur_ptr, other_ptr, cur_pitch, other_pitch, rowsize, height) >> (bits_per_pixel-8); // scale back to 8 bit range; | |
| 940 | ✗ | default: // case 4 | |
| 941 | ✗ | return calculate_sad_c<float>(cur_ptr, other_ptr, cur_pitch, other_pitch, rowsize, height); | |
| 942 | } | ||
| 943 | } | ||
| 944 | |||
| 945 | 4 | PVideoFrame TemporalSoften::GetFrame(int n, IScriptEnvironment* env) | |
| 946 | { | ||
| 947 | 4 | int radius = (kernel-1) / 2; | |
| 948 | 4 | int c = 0; | |
| 949 | |||
| 950 | // Just skip if silly settings | ||
| 951 | |||
| 952 |
2/6✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 4 times.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 10 taken 4 times.
|
4 | if ((!luma_threshold && !chroma_threshold) || !radius) |
| 953 | { | ||
| 954 | ✗ | PVideoFrame ret = child->GetFrame(n, env); // P.F. | |
| 955 | ✗ | return ret; | |
| 956 | ✗ | } | |
| 957 | |||
| 958 | bool planeDisabled[16]; | ||
| 959 | |||
| 960 |
2/2✓ Branch 12 → 11 taken 64 times.
✓ Branch 12 → 13 taken 4 times.
|
68 | for (int p = 0; p<16; p++) { |
| 961 | 64 | planeDisabled[p] = false; | |
| 962 | } | ||
| 963 | |||
| 964 | 4 | std::vector<PVideoFrame> frames; | |
| 965 |
1/2✓ Branch 14 → 15 taken 4 times.
✗ Branch 14 → 119 not taken.
|
4 | frames.reserve(kernel); |
| 966 | |||
| 967 |
2/2✓ Branch 22 → 16 taken 12 times.
✓ Branch 22 → 23 taken 4 times.
|
16 | for (int p = n - radius; p <= n + radius; ++p) { |
| 968 |
2/4✓ Branch 18 → 19 taken 12 times.
✗ Branch 18 → 115 not taken.
✓ Branch 19 → 20 taken 12 times.
✗ Branch 19 → 113 not taken.
|
12 | frames.emplace_back(child->GetFrame(clamp(p, 0, vi.num_frames - 1), env)); |
| 969 | } | ||
| 970 | |||
| 971 | // P.F. 16.04.06 leak fix r1841 after 8 days of bug chasing: | ||
| 972 | // Reason #1 of the random QTGMC memory leaks (stuck frame refcounts) | ||
| 973 | // MakeWritable alters the pointer if it is not yet writeable, thus the original PVideoFrame won't be freed (refcount decremented) | ||
| 974 | // To fix this, we leave the frame[] array in its place and copy frame[radius] to CenterFrame and make further write operations on this new frame. | ||
| 975 | // env->MakeWritable(&frames[radius]); // old culprit line. if not yet writeable -> gives another pointer | ||
| 976 |
1/2✓ Branch 24 → 25 taken 4 times.
✗ Branch 24 → 119 not taken.
|
4 | PVideoFrame CenterFrame = frames[radius]; |
| 977 |
1/2✓ Branch 25 → 26 taken 4 times.
✗ Branch 25 → 117 not taken.
|
4 | env->MakeWritable(&CenterFrame); |
| 978 | |||
| 979 | do { | ||
| 980 | const BYTE* planeP[16]; | ||
| 981 | const BYTE* planeP2[16]; | ||
| 982 | int planePitch[16]; | ||
| 983 | int planePitch2[16]; | ||
| 984 | |||
| 985 | 10 | int current_thresh = planes[c].threshold; // Threshold for current plane. | |
| 986 | 10 | int d = 0; | |
| 987 |
2/2✓ Branch 35 → 28 taken 10 times.
✓ Branch 35 → 36 taken 10 times.
|
20 | for (int i = 0; i<radius; i++) { // Fetch all planes sequencially |
| 988 |
1/2✓ Branch 30 → 31 taken 10 times.
✗ Branch 30 → 116 not taken.
|
10 | planePitch[d] = frames[i]->GetPitch(planes[c].planeId); |
| 989 |
1/2✓ Branch 33 → 34 taken 10 times.
✗ Branch 33 → 116 not taken.
|
10 | planeP[d++] = frames[i]->GetReadPtr(planes[c].planeId); |
| 990 | } | ||
| 991 | |||
| 992 | // BYTE* c_plane = frames[radius]->GetWritePtr(planes[c]); | ||
| 993 |
1/2✓ Branch 37 → 38 taken 10 times.
✗ Branch 37 → 116 not taken.
|
10 | BYTE* c_plane = CenterFrame->GetWritePtr(planes[c].planeId); // P.F. using CenterFrame for write access |
| 994 | |||
| 995 |
2/2✓ Branch 46 → 39 taken 10 times.
✓ Branch 46 → 47 taken 10 times.
|
20 | for (int i = 1; i<=radius; i++) { // Fetch all planes sequencially |
| 996 |
1/2✓ Branch 41 → 42 taken 10 times.
✗ Branch 41 → 116 not taken.
|
10 | planePitch[d] = frames[radius+i]->GetPitch(planes[c].planeId); |
| 997 |
1/2✓ Branch 44 → 45 taken 10 times.
✗ Branch 44 → 116 not taken.
|
10 | planeP[d++] = frames[radius+i]->GetReadPtr(planes[c].planeId); |
| 998 | } | ||
| 999 | |||
| 1000 |
1/2✓ Branch 48 → 49 taken 10 times.
✗ Branch 48 → 116 not taken.
|
10 | int rowsize = CenterFrame->GetRowSize(planes[c].planeId|PLANAR_ALIGNED); |
| 1001 |
1/2✓ Branch 50 → 51 taken 10 times.
✗ Branch 50 → 116 not taken.
|
10 | int h = CenterFrame->GetHeight(planes[c].planeId); |
| 1002 |
1/2✓ Branch 52 → 53 taken 10 times.
✗ Branch 52 → 116 not taken.
|
10 | int pitch = CenterFrame->GetPitch(planes[c].planeId); |
| 1003 | |||
| 1004 |
1/2✗ Branch 53 → 54 not taken.
✓ Branch 53 → 84 taken 10 times.
|
10 | if (scenechange>0) { |
| 1005 | ✗ | int d2 = 0; | |
| 1006 | ✗ | bool skiprest = false; | |
| 1007 | ✗ | for (int i = radius-1; i>=0; i--) { // Check frames backwards | |
| 1008 | ✗ | if ((!skiprest) && (!planeDisabled[i])) { | |
| 1009 | ✗ | int sad = (int)calculate_sad(c_plane, planeP[i], pitch, planePitch[i], CenterFrame->GetRowSize(planes[c].planeId), h, pixelsize, bits_per_pixel, env); | |
| 1010 | ✗ | if (sad < scenechange) { | |
| 1011 | ✗ | planePitch2[d2] = planePitch[i]; | |
| 1012 | ✗ | planeP2[d2++] = planeP[i]; | |
| 1013 | } else { | ||
| 1014 | ✗ | skiprest = true; | |
| 1015 | } | ||
| 1016 | ✗ | planeDisabled[i] = skiprest; // Disable this frame on next plane (so that Y can affect UV) | |
| 1017 | ✗ | } else { | |
| 1018 | ✗ | planeDisabled[i] = true; | |
| 1019 | } | ||
| 1020 | } | ||
| 1021 | ✗ | skiprest = false; | |
| 1022 | ✗ | for (int i = radius; i < 2*radius; i++) { // Check forward frames | |
| 1023 | ✗ | if ((!skiprest) && (!planeDisabled[i])) { // Disable this frame on next plane (so that Y can affect UV) | |
| 1024 | ✗ | int sad = (int)calculate_sad(c_plane, planeP[i], pitch, planePitch[i], CenterFrame->GetRowSize(planes[c].planeId), h, pixelsize, bits_per_pixel, env); | |
| 1025 | ✗ | if (sad < scenechange) { | |
| 1026 | ✗ | planePitch2[d2] = planePitch[i]; | |
| 1027 | ✗ | planeP2[d2++] = planeP[i]; | |
| 1028 | } else { | ||
| 1029 | ✗ | skiprest = true; | |
| 1030 | } | ||
| 1031 | ✗ | planeDisabled[i] = skiprest; | |
| 1032 | ✗ | } else { | |
| 1033 | ✗ | planeDisabled[i] = true; | |
| 1034 | } | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | //Copy back | ||
| 1038 | ✗ | for (int i = 0; i<d2; i++) { | |
| 1039 | ✗ | planeP[i] = planeP2[i]; | |
| 1040 | ✗ | planePitch[i] = planePitch2[i]; | |
| 1041 | } | ||
| 1042 | ✗ | d = d2; | |
| 1043 | } | ||
| 1044 | |||
| 1045 |
1/2✗ Branch 84 → 85 not taken.
✓ Branch 84 → 92 taken 10 times.
|
10 | if (d < 1) |
| 1046 | { | ||
| 1047 | // Memory leak reason #2 r1841: this wasn't here before return | ||
| 1048 | ✗ | for (int i = 0; i < kernel; ++i) | |
| 1049 | ✗ | frames[i] = nullptr; | |
| 1050 | // return frames[radius]; | ||
| 1051 | ✗ | return CenterFrame; // return the modified frame | |
| 1052 | } | ||
| 1053 | |||
| 1054 | 10 | int c_div = 32768/(d+1); // We also have the tetplane included, thus d+1. | |
| 1055 |
1/2✓ Branch 92 → 93 taken 10 times.
✗ Branch 92 → 103 not taken.
|
10 | if (current_thresh) { |
| 1056 | // for threshold==255 -> simple average | ||
| 1057 |
2/2✓ Branch 102 → 94 taken 35 times.
✓ Branch 102 → 103 taken 10 times.
|
45 | for (int y = 0; y<h; y++) { // One line at the time |
| 1058 |
2/4✓ Branch 94 → 95 taken 35 times.
✗ Branch 94 → 116 not taken.
✗ Branch 95 → 96 not taken.
✓ Branch 95 → 97 taken 35 times.
|
35 | if (vi.IsYUY2()) { |
| 1059 | ✗ | accumulate_line_yuy2(c_plane, planeP, d, rowsize, luma_threshold, chroma_threshold, c_div, env); | |
| 1060 | } else { | ||
| 1061 |
1/2✓ Branch 97 → 98 taken 35 times.
✗ Branch 97 → 116 not taken.
|
35 | accumulate_line(c_plane, planeP, d, rowsize, current_thresh, c_div, pixelsize, bits_per_pixel, env); |
| 1062 | } | ||
| 1063 |
2/2✓ Branch 100 → 99 taken 70 times.
✓ Branch 100 → 101 taken 35 times.
|
105 | for (int p = 0; p<d; p++) |
| 1064 | 70 | planeP[p] += planePitch[p]; | |
| 1065 | 35 | c_plane += pitch; | |
| 1066 | } | ||
| 1067 | } else { // Just maintain the plane | ||
| 1068 | } | ||
| 1069 | 10 | c++; | |
| 1070 |
2/2✓ Branch 105 → 106 taken 6 times.
✓ Branch 105 → 107 taken 4 times.
|
10 | } while (planes[c].planeId); |
| 1071 | |||
| 1072 | // PVideoFrame result = frames[radius]; // we are using CenterFrame instead | ||
| 1073 | // return result; | ||
| 1074 |
1/2✓ Branch 107 → 108 taken 4 times.
✗ Branch 107 → 117 not taken.
|
4 | return CenterFrame; |
| 1075 | 4 | } | |
| 1076 | |||
| 1077 | |||
| 1078 | ✗ | AVSValue __cdecl TemporalSoften::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 1079 | { | ||
| 1080 | ✗ | return new TemporalSoften( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(), | |
| 1081 | ✗ | args[3].AsInt(), args[4].AsInt(0),/*args[5].AsInt(1),*/env ); //ignore mode parameter | |
| 1082 | } | ||
| 1083 | |||
| 1084 | |||
| 1085 | |||
| 1086 | /**************************** | ||
| 1087 | **** Spatial Soften ***** | ||
| 1088 | ***************************/ | ||
| 1089 | |||
| 1090 | 2 | SpatialSoften::SpatialSoften( PClip _child, int _radius, unsigned _luma_threshold, | |
| 1091 | 2 | unsigned _chroma_threshold, IScriptEnvironment* env ) | |
| 1092 | : GenericVideoFilter(_child), | ||
| 1093 | 2 | luma_threshold(_luma_threshold), chroma_threshold(_chroma_threshold), | |
| 1094 |
2/4✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 9 not taken.
|
2 | diameter(_radius * 2 + 1) |
| 1095 | { | ||
| 1096 |
2/4✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 12 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 2 times.
|
2 | if (!vi.IsYUY2()) |
| 1097 | ✗ | env->ThrowError("SpatialSoften: requires YUY2 input"); | |
| 1098 | 2 | } | |
| 1099 | |||
| 1100 | |||
| 1101 | 1 | PVideoFrame SpatialSoften::GetFrame(int n, IScriptEnvironment* env) | |
| 1102 | { | ||
| 1103 |
1/2✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 59 not taken.
|
1 | PVideoFrame src = child->GetFrame(n, env); |
| 1104 |
1/2✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 57 not taken.
|
1 | PVideoFrame dst = env->NewVideoFrameP(vi, &src); |
| 1105 | |||
| 1106 |
1/2✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 55 not taken.
|
1 | const BYTE* srcp = src->GetReadPtr(); |
| 1107 |
1/2✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 55 not taken.
|
1 | BYTE* dstp = dst->GetWritePtr(); |
| 1108 |
1/2✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 55 not taken.
|
1 | int src_pitch = src->GetPitch(); |
| 1109 |
1/2✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 55 not taken.
|
1 | int dst_pitch = dst->GetPitch(); |
| 1110 |
1/2✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 55 not taken.
|
1 | int row_size = src->GetRowSize(); |
| 1111 | |||
| 1112 |
2/2✓ Branch 51 → 16 taken 3 times.
✓ Branch 51 → 52 taken 1 time.
|
4 | for (int y=0; y<vi.height; ++y) |
| 1113 | { | ||
| 1114 | const BYTE* line[65]; // better not make diameter bigger than this... | ||
| 1115 |
2/2✓ Branch 19 → 17 taken 9 times.
✓ Branch 19 → 20 taken 3 times.
|
12 | for (int h=0; h<diameter; ++h) |
| 1116 | 9 | line[h] = &srcp[src_pitch * clamp(y+h-(diameter>>1), 0, vi.height-1)]; | |
| 1117 | int x; | ||
| 1118 | |||
| 1119 | 3 | int edge = (diameter+1) & -4; | |
| 1120 |
2/2✓ Branch 22 → 21 taken 12 times.
✓ Branch 22 → 23 taken 3 times.
|
15 | for (x=0; x<edge; ++x) // diameter-1 == (diameter>>1) * 2 |
| 1121 | 12 | dstp[y*dst_pitch + x] = srcp[y*src_pitch + x]; | |
| 1122 |
2/2✓ Branch 46 → 24 taken 12 times.
✓ Branch 46 → 47 taken 3 times.
|
15 | for (; x < row_size - edge; x+=2) |
| 1123 | { | ||
| 1124 | 12 | int cnt=0, _y=0, _u=0, _v=0; | |
| 1125 | 12 | int xx = x | 3; | |
| 1126 | 12 | int Y = srcp[y*src_pitch + x], U = srcp[y*src_pitch + xx - 2], V = srcp[y*src_pitch + xx]; | |
| 1127 |
2/2✓ Branch 42 → 25 taken 36 times.
✓ Branch 42 → 43 taken 12 times.
|
48 | for (int h=0; h<diameter; ++h) |
| 1128 | { | ||
| 1129 |
2/2✓ Branch 40 → 26 taken 108 times.
✓ Branch 40 → 41 taken 36 times.
|
144 | for (int w = -diameter+1; w < diameter; w += 2) |
| 1130 | { | ||
| 1131 | 108 | int xw = (x+w) | 3; | |
| 1132 |
1/2✓ Branch 31 → 32 taken 36 times.
✗ Branch 31 → 36 not taken.
|
144 | if (IsClose(line[h][x+w], Y, luma_threshold) && IsClose(line[h][xw-2], U, |
| 1133 |
6/6✓ Branch 28 → 29 taken 36 times.
✓ Branch 28 → 36 taken 72 times.
✓ Branch 34 → 35 taken 20 times.
✓ Branch 34 → 36 taken 16 times.
✓ Branch 37 → 38 taken 20 times.
✓ Branch 37 → 39 taken 88 times.
|
180 | chroma_threshold) && IsClose(line[h][xw], V, chroma_threshold)) |
| 1134 | { | ||
| 1135 | 20 | ++cnt; _y += line[h][x+w]; _u += line[h][xw-2]; _v += line[h][xw]; | |
| 1136 | } | ||
| 1137 | } | ||
| 1138 | } | ||
| 1139 | 12 | dstp[y*dst_pitch + x] = (_y + (cnt>>1)) / cnt; | |
| 1140 |
2/2✓ Branch 43 → 44 taken 6 times.
✓ Branch 43 → 45 taken 6 times.
|
12 | if (!(x&3)) { |
| 1141 | 6 | dstp[y*dst_pitch + x+1] = (_u + (cnt>>1)) / cnt; | |
| 1142 | 6 | dstp[y*dst_pitch + x+3] = (_v + (cnt>>1)) / cnt; | |
| 1143 | } | ||
| 1144 | } | ||
| 1145 |
2/2✓ Branch 49 → 48 taken 12 times.
✓ Branch 49 → 50 taken 3 times.
|
15 | for (; x<row_size; ++x) |
| 1146 | 12 | dstp[y*dst_pitch + x] = srcp[y*src_pitch + x]; | |
| 1147 | } | ||
| 1148 | |||
| 1149 | 1 | return dst; | |
| 1150 | 1 | } | |
| 1151 | |||
| 1152 | |||
| 1153 | ✗ | AVSValue __cdecl SpatialSoften::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 1154 | { | ||
| 1155 | ✗ | return new SpatialSoften( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(), | |
| 1156 | ✗ | args[3].AsInt(), env ); | |
| 1157 | } | ||
| 1158 |