core/FilterConstructor.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "FilterConstructor.h" | ||
| 2 | #include "avisynth.h" | ||
| 3 | |||
| 4 | 7 | FilterConstructor::FilterConstructor(IScriptEnvironment2 * env, | |
| 5 | IScriptEnvironment_Avs25* env25, | ||
| 6 | IScriptEnvironment_AvsPreV11C* envPreV11C, | ||
| 7 | 7 | const Function *func, std::vector<AVSValue>* argStorage, std::vector<AVSValue>* ctorArgs) : | |
| 8 | 7 | Env(env), | |
| 9 | 7 | Env25(env25), | |
| 10 | 7 | EnvPreV11C(envPreV11C), | |
| 11 | 7 | Func(func), | |
| 12 | #if 1 | ||
| 13 | 14 | ArgStorage(std::move(*argStorage)), | |
| 14 | 14 | CtorArgs(std::move(*ctorArgs)) | |
| 15 | #else | ||
| 16 | // no need to move, subarrays could not be returned | ||
| 17 | ArgStorage(*argStorage), | ||
| 18 | CtorArgs(*ctorArgs) | ||
| 19 | #endif | ||
| 20 | { | ||
| 21 | 7 | } | |
| 22 | |||
| 23 | |||
| 24 | 7 | AVSValue FilterConstructor::InstantiateFilter() const | |
| 25 | { | ||
| 26 | // funcArgs is passed to the function as an array. | ||
| 27 | // Calls the plugin's instance creator, which is usually Filter_Create(AVSValue args, void *user_data, IScriptEnvironment *env) | ||
| 28 | // or create_c_filter | ||
| 29 |
1/2✓ Branch 2 → 3 taken 7 times.
✗ Branch 2 → 107 not taken.
|
7 | AVSValue funcArgs; |
| 30 | |||
| 31 | // isPluginAvs25 and isPluginPreV11C cannot accept long and double types in | ||
| 32 | // their parameters passed to them. | ||
| 33 | // Such plugins don't recognize 'l' and 'd' 64-bit types due to direct type field checks in AVSValue/AVS_Value. | ||
| 34 | // IsInt/avs_is_int and IsFloat/avs_is_float check the type field directly in the old header, without an interface call. | ||
| 35 | // New avisynth_c.h supports these types, but old plugins don't. | ||
| 36 | // Thus we convert 64-bit types in the parameter list to 32-bit ones. | ||
| 37 |
2/4✓ Branch 3 → 4 taken 7 times.
✗ Branch 3 → 5 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 46 taken 7 times.
|
7 | if (Func->isPluginAvs25 || Func->isPluginPreV11C) { |
| 38 | ✗ | std::vector<AVSValue> funcArgs_temp(CtorArgs.size(), AVSValue()); | |
| 39 | ✗ | for (auto i = 0; i < (int)CtorArgs.size(); i++) { | |
| 40 | ✗ | if (CtorArgs[i].GetType() == AvsValueType::VALUE_TYPE_LONG) // long int64 -> 32 bit int | |
| 41 | ✗ | funcArgs_temp[i] = CtorArgs[i].AsInt(); | |
| 42 | ✗ | else if (CtorArgs[i].GetType() == AvsValueType::VALUE_TYPE_DOUBLE) // double -> float | |
| 43 | ✗ | funcArgs_temp[i] = CtorArgs[i].AsFloatf(); | |
| 44 | else | ||
| 45 | ✗ | funcArgs_temp[i] = CtorArgs[i]; | |
| 46 | } | ||
| 47 | ✗ | funcArgs = AVSValue(funcArgs_temp.data(), (int)funcArgs_temp.size()); | |
| 48 | ✗ | } | |
| 49 | else { | ||
| 50 |
2/4✓ Branch 48 → 49 taken 7 times.
✗ Branch 48 → 98 not taken.
✓ Branch 49 → 50 taken 7 times.
✗ Branch 49 → 96 not taken.
|
7 | funcArgs = AVSValue(CtorArgs.data(), (int)CtorArgs.size()); |
| 51 | } | ||
| 52 | |||
| 53 |
1/2✓ Branch 57 → 58 taken 7 times.
✗ Branch 57 → 101 not taken.
|
14 | AVSValue retval = Func->apply(funcArgs, Func->user_data, |
| 54 | 7 | Func->isPluginAvs25 ? (IScriptEnvironment *)Env25 : | |
| 55 |
1/2✗ Branch 54 → 55 not taken.
✓ Branch 54 → 56 taken 7 times.
|
7 | Func->isPluginPreV11C ? (IScriptEnvironment*)EnvPreV11C : |
| 56 |
2/4✗ Branch 52 → 53 not taken.
✓ Branch 52 → 54 taken 7 times.
✓ Branch 58 → 59 taken 7 times.
✗ Branch 58 → 99 not taken.
|
21 | Env); |
| 57 | // pass back proper ScriptEnvironment, because a 2.5 plugin e.g. GRunT can back-Invoke ScriptClip | ||
| 58 |
1/2✗ Branch 60 → 61 not taken.
✓ Branch 60 → 75 taken 7 times.
|
7 | if (Func->isPluginAvs25) |
| 59 | { | ||
| 60 | // After instantiate a v2.5 "baked code" function, | ||
| 61 | // manually release Clips or else clip variables get stuck in memory on exit | ||
| 62 | ✗ | if (funcArgs.IsArray()) | |
| 63 | { | ||
| 64 | ✗ | for (int i = 0; i < funcArgs.ArraySize(); i++) | |
| 65 | { | ||
| 66 | ✗ | if (funcArgs[i].IsClip()) { | |
| 67 | ✗ | IClip* rawClip = (IClip*)(void*)funcArgs[i].AsClip(); // de-smart pointering | |
| 68 | ✗ | rawClip->Release(); | |
| 69 | } | ||
| 70 | } | ||
| 71 | } | ||
| 72 | // Problem: AVS 2.5 plugins have "baked code", their interface contains direct manipulation, refcount, free of AVSValue resources. | ||
| 73 | // So they do not know about array deep copy and deep free mechanism. | ||
| 74 | // Thus array sub-elements of the parameter AVSValue won't be freed up on exiting of such functions. | ||
| 75 | // Example: CtorArgs contains clip(s) with reference count N | ||
| 76 | // Upon creating funcArgs the "smart" array creation will copy the subarray as well. | ||
| 77 | // Because of the deep copy the reference count of these PClip values are increased by 1. | ||
| 78 | // Then funcArgs will be passed to the CPP 2.5 function which won't release the Array content, only destroys the | ||
| 79 | // 'holder' array-typed AVSValue, array elements will be untouched. | ||
| 80 | // So if there is a PClip parameters the Clip's reference count remains N+1, causing memory leak. | ||
| 81 | // This is why we have to release them manually, deferencing the Clip by one, instead of the plugin's code. | ||
| 82 | // If this reference count decrease is not done then env->DeleteScriptEnvironment will not free up everything. | ||
| 83 | // ScriptEnvironment destroy is freeing up variables as well. | ||
| 84 | // If a variable contains such a clip (e.g. "last"), it will fail to be released, because such Clip will not reached refcount==0. | ||
| 85 | // e.g. VirtualDub consecutively press "script reload"s. Memory will leak even 50-80Mbytes so after a while | ||
| 86 | // memory gets full. | ||
| 87 | } | ||
| 88 | 7 | return retval; | |
| 89 | 7 | } | |
| 90 |