filters/debug.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 | |||
| 36 | #include "debug.h" | ||
| 37 | |||
| 38 | #ifdef AVS_WINDOWS | ||
| 39 | #include <avs/win.h> | ||
| 40 | #else | ||
| 41 | #include <avs/posix.h> | ||
| 42 | #endif | ||
| 43 | |||
| 44 | #include "../core/bitblt.h" | ||
| 45 | #include "../core/internal.h" | ||
| 46 | |||
| 47 | |||
| 48 | |||
| 49 | /********************************************** | ||
| 50 | ******* PlanarLegacyAlignment Filter ******* | ||
| 51 | ******* for pitch challenged plugins ******* | ||
| 52 | **********************************************/ | ||
| 53 | |||
| 54 | class PlanarLegacyAlignment : public GenericVideoFilter | ||
| 55 | { | ||
| 56 | private: | ||
| 57 | const IScriptEnvironment::PlanarChromaAlignmentMode mode; | ||
| 58 | |||
| 59 | public: | ||
| 60 | 1 | PlanarLegacyAlignment( PClip _child, const bool _mode, IScriptEnvironment* env ) | |
| 61 | 1 | : GenericVideoFilter(_child), | |
| 62 | 1 | mode(_mode ? IScriptEnvironment::PlanarChromaAlignmentOff // Legacy PLANAR_Y alignment | |
| 63 |
3/6✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 9 not taken.
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 7 not taken.
|
1 | : IScriptEnvironment::PlanarChromaAlignmentOn) // New PLANAR_UV priority alignment |
| 64 | { | ||
| 65 | AVS_UNUSED(env); | ||
| 66 | 1 | } | |
| 67 | |||
| 68 | 1 | PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) | |
| 69 | { | ||
| 70 | const IScriptEnvironment::PlanarChromaAlignmentMode | ||
| 71 | 1 | oldmode = env->PlanarChromaAlignment(mode) // Set the PLANAR alignement mode | |
| 72 |
1/2✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 5 not taken.
|
1 | ? IScriptEnvironment::PlanarChromaAlignmentOn |
| 73 | 1 | : IScriptEnvironment::PlanarChromaAlignmentOff; | |
| 74 | |||
| 75 | 1 | PVideoFrame src = child->GetFrame(n, env); // run the GetFrame chain | |
| 76 | |||
| 77 | ✗ | env->PlanarChromaAlignment(oldmode); // reset the PLANAR alignement mode | |
| 78 | |||
| 79 | ✗ | return src; | |
| 80 | ✗ | } | |
| 81 | |||
| 82 | 1 | static AVSValue __cdecl Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 83 | { | ||
| 84 |
7/16✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 18 not taken.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 18 not taken.
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 17 not taken.
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 17 not taken.
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 15 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 15 not taken.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 1 time.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 20 not taken.
|
3 | return new PlanarLegacyAlignment(args[0].AsClip(), args[1].AsBool(), env); |
| 85 | } | ||
| 86 | |||
| 87 | }; | ||
| 88 | |||
| 89 | |||
| 90 | |||
| 91 | /*********************************************** | ||
| 92 | ******* Echo Filter ******* | ||
| 93 | ******* Call GetFrame on all source clips***** | ||
| 94 | ***********************************************/ | ||
| 95 | |||
| 96 | class Echo : public GenericVideoFilter | ||
| 97 | { | ||
| 98 | private: | ||
| 99 | const int ClipCount; | ||
| 100 | PClip *clips; | ||
| 101 | |||
| 102 | public: | ||
| 103 | ✗ | Echo( PClip _child, const AVSValue _clips, IScriptEnvironment* env ) | |
| 104 | ✗ | : GenericVideoFilter(_child), ClipCount(_clips.ArraySize()) { | |
| 105 | AVS_UNUSED(env); | ||
| 106 | |||
| 107 | ✗ | clips = new PClip[ClipCount]; | |
| 108 | ✗ | for (int i=0; i < ClipCount; i++) | |
| 109 | ✗ | clips[i] = _clips[i].AsClip(); | |
| 110 | ✗ | } | |
| 111 | |||
| 112 | ✗ | ~Echo() { | |
| 113 | ✗ | delete[] clips; | |
| 114 | ✗ | clips = 0; | |
| 115 | ✗ | } | |
| 116 | |||
| 117 | ✗ | PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { | |
| 118 | |||
| 119 | ✗ | PVideoFrame src = child->GetFrame(n, env); | |
| 120 | |||
| 121 | ✗ | for (int i=0; i < ClipCount; i++) | |
| 122 | ✗ | clips[i]->GetFrame(n, env); // run the GetFrame chains | |
| 123 | |||
| 124 | ✗ | return src; | |
| 125 | ✗ | } | |
| 126 | |||
| 127 | ✗ | static AVSValue __cdecl Create(AVSValue args, void*, IScriptEnvironment* env) { | |
| 128 | ✗ | return new Echo(args[0].AsClip(), args[1], env); | |
| 129 | } | ||
| 130 | |||
| 131 | }; | ||
| 132 | |||
| 133 | |||
| 134 | |||
| 135 | /*********************************************** | ||
| 136 | ****** Preroll GetFrame/GetAudio Filter ****** | ||
| 137 | ***********************************************/ | ||
| 138 | |||
| 139 | class Preroll : public GenericVideoFilter | ||
| 140 | { | ||
| 141 | private: | ||
| 142 | const int videopr; | ||
| 143 | const int64_t audiopr; | ||
| 144 | |||
| 145 | int videonext; | ||
| 146 | int64_t audionext; | ||
| 147 | |||
| 148 | public: | ||
| 149 | ✗ | Preroll( PClip _child, const int _videopr, const double _audiopr, IScriptEnvironment* env ) | |
| 150 | ✗ | : GenericVideoFilter(_child), | |
| 151 | ✗ | videopr(_videopr), | |
| 152 | ✗ | audiopr(int64_t(_audiopr*vi.audio_samples_per_second+0.5)), | |
| 153 | ✗ | videonext(0), | |
| 154 | ✗ | audionext(0) { | |
| 155 | |||
| 156 | AVS_UNUSED(env); | ||
| 157 | // Force source filter to honour preroll | ||
| 158 | ✗ | child->SetCacheHints(CACHE_NOTHING, 0); // Disable Video cache | |
| 159 | ✗ | child->SetCacheHints(CACHE_AUDIO_NOTHING, 0); // Disable Audio cache | |
| 160 | ✗ | } | |
| 161 | |||
| 162 | ✗ | PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { | |
| 163 | ✗ | if (n != videonext) { | |
| 164 | ✗ | int i = n - videopr; | |
| 165 | ✗ | if (i < 0) i = 0; | |
| 166 | |||
| 167 | // Optimise if n is within pr frames of last | ||
| 168 | ✗ | if (i < videonext && n > videonext) i = videonext; | |
| 169 | |||
| 170 | ✗ | while (i < n) { | |
| 171 | ✗ | child->GetFrame(i, env); | |
| 172 | ✗ | i += 1; | |
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | ✗ | videonext = n+1; | |
| 177 | ✗ | return child->GetFrame(n, env); | |
| 178 | } | ||
| 179 | |||
| 180 | ✗ | void __stdcall GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) { | |
| 181 | ✗ | if (start != audionext) { | |
| 182 | ✗ | int64_t s = start - audiopr; | |
| 183 | ✗ | if (s < 0) s = 0; | |
| 184 | |||
| 185 | // Optimise if start is within pr sample of last | ||
| 186 | ✗ | if (s < audionext && start > audionext) s = audionext; | |
| 187 | |||
| 188 | ✗ | while (s < start) { | |
| 189 | ✗ | int64_t c = start - s; | |
| 190 | ✗ | if (c > count) c = count; | |
| 191 | |||
| 192 | ✗ | child->GetAudio(buf, s, c, env); | |
| 193 | ✗ | s += c; | |
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | ✗ | audionext = start+count; | |
| 198 | ✗ | child->GetAudio(buf, start, count, env); | |
| 199 | ✗ | } | |
| 200 | |||
| 201 | ✗ | static AVSValue __cdecl Create(AVSValue args, void*, IScriptEnvironment* env) { | |
| 202 | ✗ | return new Preroll(args[0].AsClip(), args[1].AsInt(0), (float)args[2].AsDblDef(0.0), env); | |
| 203 | } | ||
| 204 | |||
| 205 | }; | ||
| 206 | |||
| 207 | |||
| 208 | |||
| 209 | /******************************************************************** | ||
| 210 | ***** Declare index of new filters for Avisynth's filter engine ***** | ||
| 211 | ********************************************************************/ | ||
| 212 | |||
| 213 | extern const AVSFunction Debug_filters[] = { | ||
| 214 | { "Null", BUILTIN_FUNC_PREFIX, "c[copy]s", Null::Create }, // clip, copy | ||
| 215 | { "SetPlanarLegacyAlignment", BUILTIN_FUNC_PREFIX, "cb", PlanarLegacyAlignment::Create }, // clip, legacy alignment | ||
| 216 | { "Echo", BUILTIN_FUNC_PREFIX, "cc+", Echo::Create }, | ||
| 217 | { "Preroll", BUILTIN_FUNC_PREFIX, "c[video]i[audio]f", Preroll::Create }, | ||
| 218 | { NULL } | ||
| 219 | }; | ||
| 220 | |||
| 221 | |||
| 222 | |||
| 223 | /******************************* | ||
| 224 | ******* Null Filter ******* | ||
| 225 | ******* for debugging ******* | ||
| 226 | ******************************/ | ||
| 227 | |||
| 228 | 1 | Null::Null(PClip _child, const char * _copy, IScriptEnvironment* env) | |
| 229 |
2/4✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 8 not taken.
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 6 not taken.
|
1 | : GenericVideoFilter(_child), copy(_copy) |
| 230 | { | ||
| 231 | AVS_UNUSED(env); | ||
| 232 | 1 | } | |
| 233 | |||
| 234 | 1 | Null::~Null() | |
| 235 | { | ||
| 236 | 1 | } | |
| 237 | |||
| 238 | |||
| 239 | 1 | PVideoFrame __stdcall Null::GetFrame(int n, IScriptEnvironment* env) | |
| 240 | { | ||
| 241 |
1/2✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 82 not taken.
|
1 | PVideoFrame src = child->GetFrame(n, env); |
| 242 | |||
| 243 |
1/2✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 80 not taken.
|
1 | BYTE * foo = new BYTE[256]; |
| 244 |
1/2✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 80 not taken.
|
1 | BYTE * bar = new BYTE[256]; |
| 245 |
1/2✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 80 not taken.
|
1 | MemDebug md; |
| 246 | |||
| 247 |
1/2✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 78 not taken.
|
1 | md.randomFill(foo, 8, 8, 8); |
| 248 |
1/2✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 78 not taken.
|
1 | env->BitBlt(bar, 8, foo, 8, 8, 8); |
| 249 | |||
| 250 | 1 | md.reset(); | |
| 251 |
1/2✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 78 not taken.
|
1 | int i = md.randomCheck(bar, 9, 8, 8); |
| 252 | |||
| 253 |
1/2✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 13 not taken.
|
1 | if (i) |
| 254 |
1/2✗ Branch 12 → 13 not taken.
✓ Branch 12 → 78 taken 1 time.
|
1 | env->ThrowError("bug found"); |
| 255 | |||
| 256 | ✗ | delete [] foo; | |
| 257 | ✗ | delete [] bar; | |
| 258 | |||
| 259 | ✗ | if (!lstrcmpi(copy, "makewritable")) | |
| 260 | { | ||
| 261 | ✗ | env->MakeWritable(&src); | |
| 262 | ✗ | return src; | |
| 263 | } | ||
| 264 | |||
| 265 | // TODO: no support for planar formats! | ||
| 266 | ✗ | if (!lstrcmpi(copy, "memcopy")) | |
| 267 | { | ||
| 268 | ✗ | PVideoFrame dst = env->NewVideoFrame(child->GetVideoInfo(), 16); | |
| 269 | ✗ | if (dst->IsWritable() == false) | |
| 270 | ✗ | env->ThrowError("new frame not writable"); // honestly don't know whether to expect this condition | |
| 271 | |||
| 272 | ✗ | memcpy( dst->GetWritePtr(), src->GetReadPtr(), src->GetPitch() * src->GetHeight() ); | |
| 273 | ✗ | return dst; | |
| 274 | ✗ | } | |
| 275 | |||
| 276 | ✗ | if (!lstrcmpi(copy, "bitblt")) | |
| 277 | { | ||
| 278 | ✗ | PVideoFrame dst = env->NewVideoFrame(child->GetVideoInfo(), 16); | |
| 279 | ✗ | if (dst->IsWritable() == false) | |
| 280 | ✗ | env->ThrowError("new frame not writable"); // honestly don't know whether to expect this condition | |
| 281 | |||
| 282 | ✗ | env->BitBlt( dst->GetWritePtr(), src->GetPitch(), src->GetReadPtr(), src->GetPitch(), | |
| 283 | src->GetRowSize(), src->GetHeight() ); | ||
| 284 | ✗ | return dst; | |
| 285 | ✗ | } | |
| 286 | |||
| 287 | //if (!lstrcmpi(copy, "none")) | ||
| 288 | // do nothing | ||
| 289 | ✗ | return src; | |
| 290 | 2 | } | |
| 291 | |||
| 292 | ✗ | AVSValue __cdecl Null::Create(AVSValue args, void*, IScriptEnvironment* env) | |
| 293 | { | ||
| 294 | ✗ | return new Null(args[0].AsClip(), args[1].AsString("none"), env); | |
| 295 | } | ||
| 296 | |||
| 297 | |||
| 298 | |||
| 299 | |||
| 300 | 1 | MemDebug::MemDebug() : mask(0xff) | |
| 301 | { | ||
| 302 | 1 | reset(); | |
| 303 | 1 | } | |
| 304 | |||
| 305 | |||
| 306 | 1 | MemDebug::~MemDebug() | |
| 307 | { | ||
| 308 | 1 | } | |
| 309 | |||
| 310 | |||
| 311 | // fills a buffer with "random" (the same every time) data we can | ||
| 312 | // test for after some manipulation (e.g. BitBlt) | ||
| 313 | 1 | void MemDebug::randomFill(BYTE* const buf, const int pitch, const int row_size, const int height) | |
| 314 | { | ||
| 315 |
2/2✓ Branch 8 → 3 taken 8 times.
✓ Branch 8 → 9 taken 1 time.
|
9 | for(int x=0; x<height; ++x) |
| 316 | { | ||
| 317 |
2/2✓ Branch 6 → 4 taken 64 times.
✓ Branch 6 → 7 taken 8 times.
|
72 | for(int y=0; y<row_size; ++y) |
| 318 | { | ||
| 319 | 64 | buf[x*pitch + y] = nextNum(); | |
| 320 | } | ||
| 321 | } | ||
| 322 | 1 | } | |
| 323 | |||
| 324 | |||
| 325 | // checks a buffer to see if "random" data is intact or copied correctly | ||
| 326 | // return value == offset of first discrepancy, or 0 if all's well | ||
| 327 | 1 | int MemDebug::randomCheck(BYTE* const buf, const int pitch, const int row_size, const int height) | |
| 328 | { | ||
| 329 |
1/2✓ Branch 10 → 3 taken 1 time.
✗ Branch 10 → 11 not taken.
|
1 | for(int x=0; x<height; ++x) |
| 330 | { | ||
| 331 |
1/2✓ Branch 8 → 4 taken 2 times.
✗ Branch 8 → 9 not taken.
|
2 | for(int y=0; y<row_size; ++y) |
| 332 | { | ||
| 333 | 2 | int n = nextNum(); | |
| 334 |
2/2✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 1 time.
|
2 | if (buf[x*pitch + y] != n) return x*pitch + y; |
| 335 | } | ||
| 336 | } | ||
| 337 | |||
| 338 | ✗ | return 0; | |
| 339 | } | ||
| 340 | |||
| 341 | |||
| 342 | 66 | char MemDebug::nextNum() | |
| 343 | { | ||
| 344 | 66 | ++whichByte; | |
| 345 | 66 | whichByte &= 3; | |
| 346 |
2/2✓ Branch 2 → 3 taken 17 times.
✓ Branch 2 → 4 taken 49 times.
|
66 | if (whichByte == 0) |
| 347 | { | ||
| 348 | 17 | randNum *= 0x41c64e6d; | |
| 349 | 17 | randNum += 0x3039; | |
| 350 | } | ||
| 351 | |||
| 352 | 66 | return char((randNum & (mask << (whichByte * 8))) >> (whichByte * 8)); | |
| 353 | } | ||
| 354 | |||
| 355 | |||
| 356 | 2 | void MemDebug::reset() | |
| 357 | { | ||
| 358 | 2 | randNum = -591377182; // pulled out of my ass | |
| 359 | 2 | whichByte = 3; | |
| 360 | 2 | } | |
| 361 |