GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 24.4% 95 / 0 / 389
Functions: 13.3% 2 / 0 / 15
Branches: 11.2% 110 / 0 / 979

filters/conditional/conditional.cpp
Line Branch Exec Source
1
2 // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al.
3 // http://avisynth.nl
4
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
18 // http://www.gnu.org/copyleft/gpl.html .
19 //
20 // Linking Avisynth statically or dynamically with other modules is making a
21 // combined work based on Avisynth. Thus, the terms and conditions of the GNU
22 // General Public License cover the whole combination.
23 //
24 // As a special exception, the copyright holders of Avisynth give you
25 // permission to link Avisynth with independent modules that communicate with
26 // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
27 // terms of these independent modules, and to copy and distribute the
28 // resulting combined work under terms of your choice, provided that
29 // every copy of the combined work is accompanied by a complete copy of
30 // the source code of Avisynth (the version of Avisynth used to produce the
31 // combined work), being distributed under the terms of the GNU General
32 // Public License plus this exception. An independent module is a module
33 // which is not derived from or based on Avisynth, such as 3rd-party filters,
34 // import and export plugins, or graphical user interfaces.
35
36 #include "conditional.h"
37 #include "../../core/parser/scriptparser.h"
38 #include "conditional_reader.h"
39 #include <cmath>
40
41 #ifdef AVS_WINDOWS
42 #include <avs/win.h>
43 #else
44 #include <avs/posix.h>
45 #endif
46
47 #include <avs/minmax.h>
48 #include "../../core/internal.h"
49 #include "../../core/InternalEnvironment.h"
50
51 extern const AVSFunction Conditional_filters[] = {
52 // 2020.03.28 bool "local" parameter like in gRunT. Default false. Note! AvsNeo works as local=true, but it's incompatible with old Avisynth
53 // with "function" input local default is true
54 { "ConditionalSelect", BUILTIN_FUNC_PREFIX, "csc+[show]b[local]b", ConditionalSelect::Create },
55 { "ConditionalSelect", BUILTIN_FUNC_PREFIX, "cnc+[show]b[local]b", ConditionalSelect::Create }, // function input
56 { "ConditionalFilter", BUILTIN_FUNC_PREFIX, "cccsss[show]b[local]b", ConditionalFilter::Create, (void *)0 },
57 // easy syntax from GConditionalFilter, args3 and 4 to "=" and "true":
58 { "ConditionalFilter", BUILTIN_FUNC_PREFIX, "cccs[show]b[local]b", ConditionalFilter::Create, (void *)1 },
59 { "ConditionalFilter", BUILTIN_FUNC_PREFIX, "cccn[show]b[local]b", ConditionalFilter::Create, (void *)2 }, // function input
60 { "ScriptClip", BUILTIN_FUNC_PREFIX, "cs[show]b[after_frame]b[local]b", ScriptClip::Create },
61 { "ScriptClip", BUILTIN_FUNC_PREFIX, "cn[show]b[after_frame]b[local]b", ScriptClip::Create }, // function input
62 { "ConditionalReader", BUILTIN_FUNC_PREFIX, "css[show]b[condvarsuffix]s[local]b", ConditionalReader::Create },
63 { "FrameEvaluate", BUILTIN_FUNC_PREFIX, "cs[show]b[after_frame]b[local]b", ScriptClip::Create_eval },
64 { "WriteFile", BUILTIN_FUNC_PREFIX, "c[filename]ss+[append]b[flush]b[local]b", Write::Create },
65 { "WriteFileIf", BUILTIN_FUNC_PREFIX, "c[filename]ss+[append]b[flush]b[local]b", Write::Create_If },
66 { "WriteFileStart", BUILTIN_FUNC_PREFIX, "c[filename]ss+[append]b[local]b", Write::Create_Start },
67 { "WriteFileEnd", BUILTIN_FUNC_PREFIX, "c[filename]ss+[append]b[local]b", Write::Create_End },
68 { "WriteFile", BUILTIN_FUNC_PREFIX, "c[filename]sn+[append]b[flush]b[local]b", Write::Create }, // function input
69 { "WriteFileIf", BUILTIN_FUNC_PREFIX, "c[filename]sn+[append]b[flush]b[local]b", Write::Create_If }, // function input
70 { "WriteFileStart", BUILTIN_FUNC_PREFIX, "c[filename]sn+[append]b[local]b", Write::Create_Start }, // function input
71 { "WriteFileEnd", BUILTIN_FUNC_PREFIX, "c[filename]sn+[append]b[local]b", Write::Create_End }, // function input
72 { "UseVar", BUILTIN_FUNC_PREFIX, "cs+", UseVar::Create },
73 // in conditional_reader.cpp, see property getters in conditional_functions.cpp
74
75 // value from Function
76 { "propSet", BUILTIN_FUNC_PREFIX, "csn[mode]i", SetProperty::Create, (void *)0 }, // auto from function result type
77 { "propSetInt", BUILTIN_FUNC_PREFIX, "csn[mode]i", SetProperty::Create, (void*)1 }, // forced check for int
78 { "propSetFloat", BUILTIN_FUNC_PREFIX, "csn[mode]i", SetProperty::Create, (void*)2 }, // forced check for float
79 { "propSetString", BUILTIN_FUNC_PREFIX, "csn[mode]i", SetProperty::Create, (void*)3 }, // forced check for string
80 { "propSetArray", BUILTIN_FUNC_PREFIX, "csn", SetProperty::Create, (void*)4 }, // no mode parameter, full entry refresh
81 { "propSetClip", BUILTIN_FUNC_PREFIX, "csn[mode]i", SetProperty::Create, (void*)5 }, // forced check for clip
82
83 // value from direct data
84 { "propSet", BUILTIN_FUNC_PREFIX, "csi[mode]i", SetProperty::Create, (void*)10 },
85 { "propSet", BUILTIN_FUNC_PREFIX, "csf[mode]i", SetProperty::Create, (void*)11 },
86 { "propSet", BUILTIN_FUNC_PREFIX, "css[mode]i", SetProperty::Create, (void*)12 },
87 { "propSet", BUILTIN_FUNC_PREFIX, "csa", SetProperty::Create, (void*)13 }, // no mode parameter, full entry refresh
88 { "propSet", BUILTIN_FUNC_PREFIX, "csc[mode]i", SetProperty::Create, (void*)14 },
89
90 { "propDelete", BUILTIN_FUNC_PREFIX, "cs+", DeleteProperty::Create },
91 { "propClearAll", BUILTIN_FUNC_PREFIX, "c", ClearProperties::Create },
92
93 { "propShow", BUILTIN_FUNC_PREFIX, "c[size]i[showtype]b[font]s[text_color]i[halo_color]i[bold]b[x]f[y]f[align]i[props]s+", ShowProperties::Create },
94
95 { "propCopy", BUILTIN_FUNC_PREFIX, "cc[merge]b[props]s+[exclude]b", CopyProperties::Create},
96
97 { 0 }
98 };
99
100 #define W_DIVISOR 5 // Width divisor for onscreen messages
101
102
103 /********************************
104 * Conditional Select
105 *
106 * Returns each one frame from N sources
107 * based on an integer evaluator.
108 ********************************/
109
110 ConditionalSelect::ConditionalSelect(PClip _child, AVSValue _script,
111 int _num_args, PClip *_child_array,
112 bool _show, bool _local, IScriptEnvironment* env) :
113 GenericVideoFilter(_child), script(_script),
114 num_args(_num_args), child_array(_child_array), show(_show), local(_local) {
115
116 child_devs = DEV_TYPE_ANY;
117 for (int i=0; i<num_args; i++) {
118 const VideoInfo& vin = child_array[i]->GetVideoInfo();
119
120 if (vi.height != vin.height)
121 env->ThrowError("ConditionalSelect: The sources must all have the same height!");
122
123 if (vi.width != vin.width)
124 env->ThrowError("ConditionalSelect: The sources must all have the same width!");
125
126 if (!vi.IsSameColorspace(vin))
127 env->ThrowError("ConditionalSelect: The sources must all be the same colorspace!");
128
129 if (vi.num_frames < vin.num_frames) // Max of all clips
130 vi.num_frames = vin.num_frames;
131
132 child_devs &= GetDeviceTypes(child_array[i]);
133 }
134
135 if (child_devs == 0) {
136 env->ThrowError("ConditionalSelect: No common device among sources!");
137 }
138 }
139
140
141 ConditionalSelect::~ConditionalSelect() {
142 delete[] child_array;
143 }
144
145 int __stdcall ConditionalSelect::SetCacheHints(int cachehints, int frame_range)
146 {
147 AVS_UNUSED(frame_range);
148 switch (cachehints)
149 {
150 case CACHE_GET_MTMODE:
151 return MT_NICE_FILTER;
152 case CACHE_GET_DEV_TYPE:
153 return child_devs;
154 case CACHE_GET_CHILD_DEV_TYPE:
155 return DEV_TYPE_ANY;
156 }
157 return 0; // We do not pass cache requests upwards.
158 }
159
160 PVideoFrame __stdcall ConditionalSelect::GetFrame(int n, IScriptEnvironment* env_)
161 {
162 InternalEnvironment* IEnv = GetAndRevealCamouflagedEnv(env_);
163 IScriptEnvironment* env = static_cast<IScriptEnvironment*>(IEnv);
164
165 AVSValue prev_last;
166 AVSValue prev_current_frame;
167 std::unique_ptr<GlobalVarFrame> var_frame;
168
169 AVSValue child_val = child;
170
171 if (!local) {
172 prev_last = env->GetVarDef("last"); // Store previous last
173 prev_current_frame = env->GetVarDef("current_frame"); // Store previous current_frame
174 env->SetVar("last", child_val); // Set implicit last
175 env->SetVar("current_frame", (AVSValue)n); // Set frame to be tested by the conditional filters.
176 }
177 else {
178 // Neo's default, correct but incompatible with previous Avisynth versions
179 var_frame = std::unique_ptr<GlobalVarFrame>(new GlobalVarFrame(IEnv)); // allocate new frame
180 env->SetGlobalVar("last", child_val); // Set explicit last
181 env->SetGlobalVar("current_frame", (AVSValue)n); // Set frame to be tested by the conditional filters.
182 }
183
184 AVSValue result;
185
186 try {
187 if (script.IsString()) {
188 ScriptParser parser(env, script.AsString(), "[Conditional Select, Expression]");
189 PExpression exp = parser.Parse();
190 result = exp->Evaluate(env);
191 }
192 else {
193 //auto& func = script.AsFunction(); // c++ strict conformance: cannot Convert PFunction to PFunction&
194 const PFunction& func = script.AsFunction();
195 const AVSValue empty_args_array = AVSValue(nullptr, 0); // Invoke_ parameter is const AVSValue&, don't do it inline.
196 if (!IEnv->Invoke_(&result, child_val,
197 func->GetLegacyName(), func->GetDefinition(), empty_args_array, 0))
198 {
199 env->ThrowError(
200 "ConditionalSelect: Invalid function parameter type '%s'(%s)\n"
201 "Function should have one clip argument or no argument",
202 func->GetDefinition()->param_types, func->ToString(env));
203 }
204 }
205
206 if (!result.IsInt())
207 env->ThrowError("Conditional Select: Expression must return an integer!");
208 }
209 catch (const AvisynthError &error) {
210 if (!local) {
211 env->SetVar("last", prev_last); // Restore implicit last
212 env->SetVar("current_frame", prev_current_frame); // Restore current_frame
213 }
214
215 const int num_frames = child->GetVideoInfo().num_frames;
216 PVideoFrame dst = child->GetFrame(min(num_frames-1, n), env);
217
218 env->MakeWritable(&dst);
219 env->ApplyMessageEx(&dst, vi, error.msg, vi.width/W_DIVISOR, 0xa0a0a0, 0, 0, true);
220
221 return dst;
222 }
223
224 if (!local) {
225 env->SetVar("last", prev_last); // Restore implicit last
226 env->SetVar("current_frame", prev_current_frame); // Restore current_frame
227 }
228
229 const int i = result.AsInt();
230
231 PVideoFrame dst;
232
233 if (i < 0 || i >= num_args) {
234 const int num_frames = child->GetVideoInfo().num_frames;
235 dst = child->GetFrame(min(num_frames-1, n), env);
236 }
237 else {
238 const int num_frames = child_array[i]->GetVideoInfo().num_frames;
239 dst = child_array[i]->GetFrame(min(num_frames-1, n), env);
240 }
241
242 if (show) {
243 char text[32];
244
245 snprintf(text, sizeof(text)-1, "Expression Result:%i\n", result.AsInt());
246 text[sizeof(text)-1] = '\0';
247
248 env->MakeWritable(&dst);
249 env->ApplyMessage(&dst, vi, text, vi.width/4, 0xa0a0a0, 0, 0);
250 }
251
252 return dst;
253 }
254
255
256 AVSValue __cdecl ConditionalSelect::Create(AVSValue args, void* , IScriptEnvironment* env)
257 {
258 int num_args = 0;
259 PClip* child_array = 0;
260
261 if(!args[1].IsFunction() && (!args[1].IsString() || !args[1].AsString(nullptr)))
262 env->ThrowError("Conditional Select: expression missing!");
263
264 if (args[2].IsArray()) {
265 num_args = args[2].ArraySize();
266 child_array = new PClip[num_args];
267
268 for (int i = 0; i < num_args; ++i) // Copy clips
269 child_array[i] = args[2][i].AsClip();
270 }
271 else if (args[2].IsClip()) { // Make easy to call with trivial 1 clip
272 num_args = 1;
273 child_array = new PClip[1];
274
275 child_array[0] = args[2].AsClip();
276 }
277 else {
278 env->ThrowError("Conditional Select: clip array not recognized!");
279 }
280
281 const bool runtime_local_default = args[1].IsFunction() ? true : false; // Avisynth compatibility: false, Neo: true. functions are legacy Neo
282
283 return new ConditionalSelect(args[0].AsClip(), args[1], num_args, child_array, args[3].AsBool(false), args[4].AsBool(runtime_local_default), env);
284 }
285
286
287 /********************************
288 * Conditional filter
289 *
290 * Returns each one frame from two sources,
291 * based on an evaluator.
292 ********************************/
293
294 3 ConditionalFilter::ConditionalFilter(PClip _child, PClip _source1, PClip _source2,
295 AVSValue _condition1, AVSValue _evaluator, AVSValue _condition2,
296 3 bool _show, bool _local, IScriptEnvironment* env) :
297
1/2
✓ Branch 6 → 7 taken 3 times.
✗ Branch 6 → 64 not taken.
3 GenericVideoFilter(_child), source1(_source1), source2(_source2),
298
5/10
✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 56 not taken.
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 54 not taken.
✓ Branch 5 → 6 taken 3 times.
✗ Branch 5 → 66 not taken.
✓ Branch 7 → 8 taken 3 times.
✗ Branch 7 → 62 not taken.
✓ Branch 8 → 9 taken 3 times.
✗ Branch 8 → 60 not taken.
6 eval1(_condition1), eval2(_condition2), show(_show), local(_local) {
299
300 3 evaluator = NONE;
301
302
1/2
✓ Branch 9 → 10 taken 3 times.
✗ Branch 9 → 57 not taken.
3 if (lstrcmpi(_evaluator.AsString(), "equals") == 0 ||
303
6/8
✓ Branch 10 → 11 taken 3 times.
✗ Branch 10 → 15 not taken.
✓ Branch 11 → 12 taken 3 times.
✗ Branch 11 → 57 not taken.
✓ Branch 12 → 13 taken 2 times.
✓ Branch 12 → 15 taken 1 time.
✓ Branch 17 → 18 taken 1 time.
✓ Branch 17 → 19 taken 2 times.
5 lstrcmpi(_evaluator.AsString(), "=") == 0 ||
304
2/4
✓ Branch 13 → 14 taken 2 times.
✗ Branch 13 → 57 not taken.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 2 times.
2 lstrcmpi(_evaluator.AsString(), "==") == 0)
305 1 evaluator = EQUALS;
306
7/10
✓ Branch 19 → 20 taken 3 times.
✗ Branch 19 → 57 not taken.
✓ Branch 20 → 21 taken 3 times.
✗ Branch 20 → 23 not taken.
✓ Branch 21 → 22 taken 3 times.
✗ Branch 21 → 57 not taken.
✓ Branch 22 → 23 taken 2 times.
✓ Branch 22 → 24 taken 1 time.
✓ Branch 25 → 26 taken 2 times.
✓ Branch 25 → 27 taken 1 time.
3 if (lstrcmpi(_evaluator.AsString(), "greaterthan") == 0 || lstrcmpi(_evaluator.AsString(), ">") == 0)
307 2 evaluator = GREATERTHAN;
308
5/10
✓ Branch 27 → 28 taken 3 times.
✗ Branch 27 → 57 not taken.
✓ Branch 28 → 29 taken 3 times.
✗ Branch 28 → 31 not taken.
✓ Branch 29 → 30 taken 3 times.
✗ Branch 29 → 57 not taken.
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 3 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 3 times.
3 if (lstrcmpi(_evaluator.AsString(), "lessthan") == 0 || lstrcmpi(_evaluator.AsString(), "<") == 0)
309 evaluator = LESSTHAN;
310
311
1/2
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 3 times.
3 if (evaluator == NONE)
312 env->ThrowError("ConditionalFilter: Evaluator could not be recognized!");
313
314
1/2
✓ Branch 38 → 39 taken 3 times.
✗ Branch 38 → 57 not taken.
3 VideoInfo vi1 = source1->GetVideoInfo();
315
1/2
✓ Branch 40 → 41 taken 3 times.
✗ Branch 40 → 57 not taken.
3 VideoInfo vi2 = source2->GetVideoInfo();
316
317
1/2
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 43 taken 3 times.
3 if (vi1.height != vi2.height)
318 env->ThrowError("ConditionalFilter: The two sources must have the same height!");
319
1/2
✗ Branch 43 → 44 not taken.
✓ Branch 43 → 45 taken 3 times.
3 if (vi1.width != vi2.width)
320 env->ThrowError("ConditionalFilter: The two sources must have the same width!");
321
2/4
✓ Branch 45 → 46 taken 3 times.
✗ Branch 45 → 57 not taken.
✗ Branch 46 → 47 not taken.
✓ Branch 46 → 48 taken 3 times.
3 if (!vi1.IsSameColorspace(vi2))
322 env->ThrowError("ConditionalFilter: The two sources must be the same colorspace!");
323
324 3 vi.height = vi1.height;
325 3 vi.width = vi1.width;
326 3 vi.pixel_type = vi1.pixel_type;
327 3 vi.num_frames = max(vi1.num_frames,vi2.num_frames);
328 3 vi.num_audio_samples = vi1.num_audio_samples;
329 3 vi.audio_samples_per_second = vi1.audio_samples_per_second;
330 3 vi.image_type = vi1.image_type;
331 3 vi.fps_denominator = vi1.fps_denominator;
332 3 vi.fps_numerator = vi1.fps_numerator;
333 3 vi.nchannels = vi1.nchannels;
334 3 vi.sample_type = vi1.sample_type;
335
336
2/4
✓ Branch 49 → 50 taken 3 times.
✗ Branch 49 → 57 not taken.
✓ Branch 50 → 51 taken 3 times.
✗ Branch 50 → 57 not taken.
3 child_devs = (GetDeviceTypes(source1) & GetDeviceTypes(source2));
337
338
1/2
✗ Branch 51 → 52 not taken.
✓ Branch 51 → 53 taken 3 times.
3 if (child_devs == 0) {
339 env->ThrowError("ConditionalFilter: The two sources must support the same device!");
340 }
341 3 }
342
343 const char* const t_TRUE="TRUE";
344 const char* const t_FALSE="FALSE";
345
346 int __stdcall ConditionalFilter::SetCacheHints(int cachehints, int frame_range)
347 {
348 AVS_UNUSED(frame_range);
349 switch (cachehints)
350 {
351 case CACHE_GET_MTMODE:
352 return MT_NICE_FILTER;
353 case CACHE_GET_DEV_TYPE:
354 return child_devs;
355 case CACHE_GET_CHILD_DEV_TYPE:
356 return DEV_TYPE_ANY;
357 }
358 return 0; // We do not pass cache requests upwards.
359 }
360
361 3 PVideoFrame __stdcall ConditionalFilter::GetFrame(int n, IScriptEnvironment* env_)
362 {
363
1/2
✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 300 not taken.
3 InternalEnvironment* IEnv = GetAndRevealCamouflagedEnv(env_);
364 3 IScriptEnvironment* env = static_cast<IScriptEnvironment*>(IEnv);
365
366
1/2
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 300 not taken.
3 AVSValue prev_last;
367
1/2
✓ Branch 4 → 5 taken 3 times.
✗ Branch 4 → 298 not taken.
3 AVSValue prev_current_frame;
368 3 std::unique_ptr<GlobalVarFrame> var_frame;
369
370
1/2
✓ Branch 5 → 6 taken 3 times.
✗ Branch 5 → 294 not taken.
3 AVSValue child_val = child;
371
372
1/2
✓ Branch 6 → 7 taken 3 times.
✗ Branch 6 → 24 not taken.
3 if (!local) {
373
3/6
✓ Branch 7 → 8 taken 3 times.
✗ Branch 7 → 210 not taken.
✓ Branch 8 → 9 taken 3 times.
✗ Branch 8 → 208 not taken.
✓ Branch 9 → 10 taken 3 times.
✗ Branch 9 → 206 not taken.
3 prev_last = env->GetVarDef("last"); // Store previous last
374
3/6
✓ Branch 12 → 13 taken 3 times.
✗ Branch 12 → 216 not taken.
✓ Branch 13 → 14 taken 3 times.
✗ Branch 13 → 214 not taken.
✓ Branch 14 → 15 taken 3 times.
✗ Branch 14 → 212 not taken.
3 prev_current_frame = env->GetVarDef("current_frame"); // Store previous current_frame
375
2/4
✓ Branch 17 → 18 taken 3 times.
✗ Branch 17 → 220 not taken.
✓ Branch 18 → 19 taken 3 times.
✗ Branch 18 → 218 not taken.
3 env->SetVar("last", (AVSValue)child_val); // Set implicit last
376
2/4
✓ Branch 20 → 21 taken 3 times.
✗ Branch 20 → 223 not taken.
✓ Branch 21 → 22 taken 3 times.
✗ Branch 21 → 221 not taken.
3 env->SetVar("current_frame", (AVSValue)n); // Set frame to be tested by the conditional filters.
377 }
378 else {
379 // Neo's default, correct but incompatible with previous Avisynth versions
380 var_frame = std::unique_ptr<GlobalVarFrame>(new GlobalVarFrame(IEnv)); // allocate new frame
381 env->SetGlobalVar("last", child_val); // Set explicit last
382 env->SetGlobalVar("current_frame", (AVSValue)n); // Set frame to be tested by the conditional filters.
383 }
384
385
1/2
✓ Branch 37 → 38 taken 3 times.
✗ Branch 37 → 292 not taken.
3 VideoInfo vi1 = source1->GetVideoInfo();
386
1/2
✓ Branch 39 → 40 taken 3 times.
✗ Branch 39 → 292 not taken.
3 VideoInfo vi2 = source2->GetVideoInfo();
387
388
1/2
✓ Branch 40 → 41 taken 3 times.
✗ Branch 40 → 292 not taken.
3 AVSValue e1_result;
389
1/2
✓ Branch 41 → 42 taken 3 times.
✗ Branch 41 → 290 not taken.
3 AVSValue e2_result;
390 try {
391
2/4
✓ Branch 42 → 43 taken 3 times.
✗ Branch 42 → 251 not taken.
✓ Branch 43 → 44 taken 3 times.
✗ Branch 43 → 62 not taken.
3 if (eval1.IsString()) {
392
2/4
✓ Branch 44 → 45 taken 3 times.
✗ Branch 44 → 242 not taken.
✓ Branch 45 → 46 taken 3 times.
✗ Branch 45 → 242 not taken.
3 ScriptParser parser(env, eval1.AsString(), "[Conditional Filter, Expresion 1]");
393
1/2
✓ Branch 46 → 47 taken 3 times.
✗ Branch 46 → 242 not taken.
3 PExpression exp = parser.Parse();
394
2/4
✓ Branch 48 → 49 taken 3 times.
✗ Branch 48 → 233 not taken.
✓ Branch 49 → 50 taken 3 times.
✗ Branch 49 → 231 not taken.
3 e1_result = exp->Evaluate(env);
395
396
2/4
✓ Branch 51 → 52 taken 3 times.
✗ Branch 51 → 240 not taken.
✓ Branch 52 → 53 taken 3 times.
✗ Branch 52 → 240 not taken.
3 ScriptParser parser2(env, eval2.AsString(), "[Conditional Filter, Expression 2]");
397
2/4
✓ Branch 53 → 54 taken 3 times.
✗ Branch 53 → 236 not taken.
✓ Branch 54 → 55 taken 3 times.
✗ Branch 54 → 234 not taken.
3 exp = parser2.Parse();
398
2/4
✓ Branch 57 → 58 taken 3 times.
✗ Branch 57 → 239 not taken.
✓ Branch 58 → 59 taken 3 times.
✗ Branch 58 → 237 not taken.
3 e2_result = exp->Evaluate(env);
399 3 }
400 else {
401 //auto& func = eval1.AsFunction(); // c++ strict conformance: cannot Convert PFunction to PFunction&
402 const PFunction& func = eval1.AsFunction();
403 const AVSValue empty_args_array = AVSValue(nullptr, 0); // Invoke_ parameter is const AVSValue&, don't do it inline.
404 if (!IEnv->Invoke_(&e1_result, child_val,
405 func->GetLegacyName(), func->GetDefinition(), empty_args_array, 0))
406 {
407 env->ThrowError(
408 "ConditionalFilter: Invalid function parameter type '%s'(%s)\n"
409 "Function should have one clip argument or no argument",
410 func->GetDefinition()->param_types, func->ToString(env));
411 }
412 e2_result = true;
413 }
414 } catch (const AvisynthError &error) {
415 const char* error_msg = error.msg;
416
417 PVideoFrame dst = source1->GetFrame(n,env);
418 env->MakeWritable(&dst);
419 env->ApplyMessageEx(&dst, vi1, error_msg, vi.width/W_DIVISOR, 0xa0a0a0, 0, 0, true);
420
421 if (!local) {
422 env->SetVar("last", prev_last); // Restore implicit last
423 env->SetVar("current_frame", prev_current_frame); // Restore current_frame
424 }
425
426 return dst;
427 }
428
429
1/2
✓ Branch 81 → 82 taken 3 times.
✗ Branch 81 → 84 not taken.
3 if (!local) {
430
1/2
✓ Branch 82 → 83 taken 3 times.
✗ Branch 82 → 288 not taken.
3 env->SetVar("last", prev_last); // Restore implicit last
431
1/2
✓ Branch 83 → 84 taken 3 times.
✗ Branch 83 → 288 not taken.
3 env->SetVar("current_frame", prev_current_frame); // Restore current_frame
432 }
433
434 3 bool test_int=false;
435 3 bool test_string=false;
436
437 3 int e1 = 0;
438 3 int e2 = 0;
439 3 double f1 = 0.0;
440 3 double f2 = 0.0;
441 try {
442
2/4
✓ Branch 84 → 85 taken 3 times.
✗ Branch 84 → 269 not taken.
✗ Branch 85 → 86 not taken.
✓ Branch 85 → 92 taken 3 times.
3 if (e1_result.IsString()) {
443 if (!e2_result.IsString())
444 env->ThrowError("Conditional filter: Second expression did not return a string, as in first string expression.");
445 test_string = true;
446 test_int = true;
447 e1 = lstrcmp(e1_result.AsString(), e2_result.AsString());
448 e2 = 0;
449
450
2/4
✓ Branch 92 → 93 taken 3 times.
✗ Branch 92 → 269 not taken.
✗ Branch 93 → 94 not taken.
✓ Branch 93 → 109 taken 3 times.
3 } else if (e1_result.IsBool()) {
451 if (!(e2_result.IsInt() || e2_result.IsBool()))
452 env->ThrowError("Conditional filter: Second expression did not return an integer or bool, as in first bool expression.");
453 test_int = true;
454 e1 = e1_result.AsBool();
455 e2 = e2_result.IsInt() ? e2_result.AsInt() : e2_result.AsBool();
456
457
3/4
✓ Branch 109 → 110 taken 3 times.
✗ Branch 109 → 269 not taken.
✓ Branch 110 → 111 taken 1 time.
✓ Branch 110 → 131 taken 2 times.
3 } else if (e1_result.IsInt()) {
458
3/10
✓ Branch 111 → 112 taken 1 time.
✗ Branch 111 → 269 not taken.
✗ Branch 112 → 113 not taken.
✓ Branch 112 → 115 taken 1 time.
✗ Branch 113 → 114 not taken.
✗ Branch 113 → 269 not taken.
✗ Branch 114 → 115 not taken.
✗ Branch 114 → 116 not taken.
✓ Branch 117 → 118 taken 1 time.
✗ Branch 117 → 125 not taken.
1 if (e2_result.IsInt() || e2_result.IsBool()) {
459 1 test_int = true;
460
1/2
✓ Branch 118 → 119 taken 1 time.
✗ Branch 118 → 269 not taken.
1 e1 = e1_result.AsInt();
461
3/8
✓ Branch 119 → 120 taken 1 time.
✗ Branch 119 → 269 not taken.
✓ Branch 120 → 121 taken 1 time.
✗ Branch 120 → 123 not taken.
✓ Branch 121 → 122 taken 1 time.
✗ Branch 121 → 269 not taken.
✗ Branch 123 → 124 not taken.
✗ Branch 123 → 269 not taken.
1 e2 = e2_result.IsInt() ? e2_result.AsInt() : e2_result.AsBool();
462 } else if (e2_result.IsFloat()) {
463 f1 = (float)e1_result.AsFloat();
464 f2 = (float)e2_result.AsFloat();
465 } else
466 env->ThrowError("Conditional filter: Second expression did not return a float, integer or bool, as in first integer expression.");
467
468
2/4
✓ Branch 131 → 132 taken 2 times.
✗ Branch 131 → 269 not taken.
✓ Branch 132 → 133 taken 2 times.
✗ Branch 132 → 139 not taken.
2 } else if (e1_result.IsFloat()) {
469
1/2
✓ Branch 133 → 134 taken 2 times.
✗ Branch 133 → 269 not taken.
2 f1 = (float)e1_result.AsFloat();
470
3/4
✓ Branch 134 → 135 taken 2 times.
✗ Branch 134 → 269 not taken.
✓ Branch 135 → 136 taken 1 time.
✓ Branch 135 → 137 taken 1 time.
2 if (!e2_result.IsFloat())
471
1/2
✗ Branch 136 → 137 not taken.
✓ Branch 136 → 269 taken 1 time.
1 env->ThrowError("Conditional filter: Second expression did not return a float or an integer, as in first float expression.");
472
1/2
✓ Branch 137 → 138 taken 1 time.
✗ Branch 137 → 269 not taken.
1 f2 = (float)e2_result.AsFloat();
473 } else {
474 env->ThrowError("ConditionalFilter: First expression did not return an integer, bool or float!");
475 }
476
1/2
✗ Branch 269 → 270 not taken.
✓ Branch 269 → 271 taken 1 time.
1 } catch (const AvisynthError &error) {
477 1 const char* error_msg = error.msg;
478
479
1/2
✗ Branch 273 → 274 not taken.
✓ Branch 273 → 282 taken 1 time.
1 PVideoFrame dst = source1->GetFrame(n,env);
480 env->MakeWritable(&dst);
481 env->ApplyMessageEx(&dst, vi1, error_msg, vi.width/W_DIVISOR, 0xa0a0a0, 0, 0, true);
482 return dst;
483 1 }
484
485
486 2 bool state = false;
487
488
2/2
✓ Branch 140 → 141 taken 1 time.
✓ Branch 140 → 150 taken 1 time.
2 if (test_int) { // String and Int compare
489
1/2
✗ Branch 141 → 142 not taken.
✓ Branch 141 → 144 taken 1 time.
1 if (evaluator == EQUALS)
490 if (e1 == e2) state = true;
491
492
1/2
✓ Branch 144 → 145 taken 1 time.
✗ Branch 144 → 147 not taken.
1 if (evaluator == GREATERTHAN)
493
1/2
✗ Branch 145 → 146 not taken.
✓ Branch 145 → 147 taken 1 time.
1 if (e1 > e2) state = true;
494
495
1/2
✗ Branch 147 → 148 not taken.
✓ Branch 147 → 159 taken 1 time.
1 if (evaluator == LESSTHAN)
496 if (e1 < e2) state = true;
497
498 } else { // Float compare
499
1/2
✗ Branch 150 → 151 not taken.
✓ Branch 150 → 153 taken 1 time.
1 if (evaluator == EQUALS)
500 if (fabs(f1-f2)<0.000001) state = true; // Exact equal will sometimes be rounded to wrong values.
501
502
1/2
✓ Branch 153 → 154 taken 1 time.
✗ Branch 153 → 156 not taken.
1 if (evaluator == GREATERTHAN)
503
1/2
✗ Branch 154 → 155 not taken.
✓ Branch 154 → 156 taken 1 time.
1 if (f1 > f2) state = true;
504
505
1/2
✗ Branch 156 → 157 not taken.
✓ Branch 156 → 159 taken 1 time.
1 if (evaluator == LESSTHAN)
506 if (f1 < f2) state = true;
507 }
508
509
1/2
✗ Branch 159 → 160 not taken.
✓ Branch 159 → 189 taken 2 times.
2 if (show) {
510 char text[400];
511 if (test_string) {
512 snprintf(text, sizeof(text)-1,
513 "Left side Conditional Result:%.40s\n"
514 "Right side Conditional Result:%.40s\n"
515 "Evaluate result: %s\n",
516 e1_result.AsString(), e2_result.AsString(), (state) ? t_TRUE : t_FALSE
517 );
518 } else if (test_int) {
519 snprintf(text, sizeof(text)-1,
520 "Left side Conditional Result:%i\n"
521 "Right side Conditional Result:%i\n"
522 "Evaluate result: %s\n",
523 e1, e2, (state) ? t_TRUE : t_FALSE
524 );
525 } else {
526 snprintf(text, sizeof(text)-1,
527 "Left side Conditional Result:%7.4f\n"
528 "Right side Conditional Result:%7.4f\n"
529 "Evaluate result: %s\n",
530 f1, f2, (state) ? t_TRUE : t_FALSE
531 );
532 }
533
534 PVideoFrame dst = (state) ? source1->GetFrame(min(vi1.num_frames-1,n),env) : source2->GetFrame(min(vi2.num_frames-1,n),env);
535 env->MakeWritable(&dst);
536 env->ApplyMessage(&dst, vi, text, vi.width/4, 0xa0a0a0, 0, 0);
537 return dst;
538 }
539
540
1/2
✗ Branch 189 → 190 not taken.
✓ Branch 189 → 194 taken 2 times.
2 if (state)
541 return source1->GetFrame(min(vi1.num_frames-1,n),env);
542
543
2/2
✓ Branch 196 → 197 taken 1 time.
✓ Branch 196 → 288 taken 1 time.
2 return source2->GetFrame(min(vi1.num_frames-1,n),env);
544 13 }
545
546 void __stdcall ConditionalFilter::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env) {
547 source1->GetAudio(buf, start, count, env);
548 }
549
550
551 AVSValue __cdecl ConditionalFilter::Create(AVSValue args, void* user_data, IScriptEnvironment* env)
552 {
553 intptr_t userdata = (intptr_t)user_data;
554
555 const bool runtime_local_default = args[3].IsFunction() ? true : false; // Avisynth compatibility: false, Neo: true. functions are legacy Neo
556
557 if (userdata == 0)
558 return new ConditionalFilter(args[0].AsClip(), args[1].AsClip(), args[2].AsClip(), args[3], args[4], args[5], args[6].AsBool(false), args[7].AsBool(runtime_local_default), env);
559 else // like GConditional filter shortcut: no "=" "true" needed
560 return new ConditionalFilter(args[0].AsClip(), args[1].AsClip(), args[2].AsClip(), args[3], "=", "true", args[4].AsBool(false), args[5].AsBool(runtime_local_default), env);
561 }
562
563
564 /**************************
565 * ScriptClip.
566 *
567 * Returns the value of a script evaluated at each frame.
568 *
569 * Implicit last, and current frame is set on each frame.
570 **************************/
571
572 ScriptClip::ScriptClip(PClip _child, AVSValue _script, bool _show, bool _only_eval, bool _eval_after_frame, bool _local, IScriptEnvironment* env) :
573 GenericVideoFilter(_child), script(_script), show(_show), only_eval(_only_eval), eval_after(_eval_after_frame), local(_local) {
574 AVS_UNUSED(env);
575 }
576
577
578 int __stdcall ScriptClip::SetCacheHints(int cachehints, int frame_range)
579 {
580 switch (cachehints)
581 {
582 case CACHE_GET_MTMODE:
583 return MT_NICE_FILTER;
584 case CACHE_GET_DEV_TYPE:
585 return (child->GetVersion() >= 5) ? child->SetCacheHints(CACHE_GET_DEV_TYPE, 0) : 0;
586 }
587 return 0; // We do not pass cache requests upwards.
588 }
589
590 PVideoFrame __stdcall ScriptClip::GetFrame(int n, IScriptEnvironment* env_)
591 {
592
593 InternalEnvironment* IEnv = GetAndRevealCamouflagedEnv(env_);
594 IScriptEnvironment* env = static_cast<IScriptEnvironment*>(IEnv);
595
596 AVSValue prev_last;
597 AVSValue prev_current_frame;
598 std::unique_ptr<GlobalVarFrame> var_frame;
599
600 AVSValue child_val = child;
601
602 if (!local) {
603 prev_last = env->GetVarDef("last"); // Store previous last
604 prev_current_frame = env->GetVarDef("current_frame"); // Store previous current_frame
605 env->SetVar("last", (AVSValue)child_val); // Set implicit last
606 env->SetVar("current_frame", (AVSValue)n); // Set frame to be tested by the conditional filters.
607 }
608 else {
609 // Neo's default, correct but incompatible with previous Avisynth versions
610 var_frame = std::unique_ptr<GlobalVarFrame>(new GlobalVarFrame(IEnv)); // allocate new frame
611 env->SetGlobalVar("last", child_val); // Set explicit last
612 env->SetGlobalVar("current_frame", (AVSValue)n); // Set frame to be tested by the conditional filters.
613 }
614
615 if (show) {
616 PVideoFrame dst = child->GetFrame(n,env);
617 const char* text = script.IsString() ? script.AsString() : script.AsFunction()->ToString(env);
618 env->MakeWritable(&dst);
619 env->ApplyMessage(&dst, vi, text, vi.width/6, 0xa0a0a0, 0, 0);
620 if (!local) {
621 env->SetVar("last", prev_last); // Restore implicit last
622 env->SetVar("current_frame", prev_current_frame); // Restore current_frame
623 }
624 return dst;
625 }
626
627 AVSValue result;
628 PVideoFrame eval_return; // Frame to be returned if script should be evaluated AFTER frame has been fetched. Otherwise not used.
629
630 if (eval_after) eval_return = child->GetFrame(n,env);
631
632 try {
633 if (script.IsString()) {
634 ScriptParser parser(env, script.AsString(), "[ScriptClip]");
635 PExpression exp = parser.Parse();
636 result = exp->Evaluate(env);
637 }
638 else {
639 const PFunction& func = script.AsFunction();
640 const AVSValue empty_args_array = AVSValue(nullptr, 0); // Invoke_ parameter is const AVSValue&, don't do it inline.
641 const Function* fd = func->GetDefinition();
642 if (!IEnv->Invoke_(&result, child_val,
643 func->GetLegacyName(),fd , empty_args_array, 0))
644 {
645 /* fd is nullptr:
646 ps = function propSetterFunc(Clip c) { propSetInt("frameluma_sc_func",func(AverageLuma)) }
647 ScriptClip(func(ps))
648 */
649 if (fd == nullptr)
650 env->ThrowError(
651 "ScriptClip: Invalid function parameter type '%s'(%s)\n"
652 "Function should have one clip argument or no argument",
653 "<no definition>", func->ToString(env));
654 else
655 env->ThrowError(
656 "ScriptClip: Invalid function parameter type '%s'(%s)\n"
657 "Function should have one clip argument or no argument",
658 func->GetDefinition()->param_types, func->ToString(env));
659 }
660 }
661 } catch (const AvisynthError &error) {
662 const char* error_msg = error.msg;
663
664 PVideoFrame dst = child->GetFrame(n,env);
665 env->MakeWritable(&dst);
666 env->ApplyMessageEx(&dst, vi, error_msg, vi.width/W_DIVISOR, 0xa0a0a0, 0, 0, true);
667 if (!local) {
668 env->SetVar("last", prev_last); // Restore implicit last
669 env->SetVar("current_frame", prev_current_frame); // Restore current_frame
670 }
671 return dst;
672 }
673
674 if (!local) {
675 env->SetVar("last", prev_last); // Restore implicit last
676 env->SetVar("current_frame", prev_current_frame); // Restore current_frame
677 }
678
679 if (eval_after && only_eval) return eval_return;
680 if (only_eval) return child->GetFrame(n,env);
681
682 const char* error = NULL;
683 VideoInfo vi2 = vi;
684 if (!result.IsClip()) {
685 if (result.IsBool())
686 error = "ScriptClip: Function did not return a video clip! (Was a bool)";
687 else if (result.IsInt())
688 error = "ScriptClip: Function did not return a video clip! (Was an int)";
689 else if (result.IsFloat())
690 error = "ScriptClip: Function did not return a video clip! (Was a float)";
691 else if (result.IsString())
692 error = "ScriptClip: Function did not return a video clip! (Was a string)";
693 else if (result.IsArray())
694 error = "ScriptClip: Function did not return a video clip! (Was an array)";
695 else if (!result.Defined())
696 error = "ScriptClip: Function did not return a video clip! (Was the undefined value)";
697 else
698 error = "ScriptClip: Function did not return a video clip! (type is unknown)";
699 } else {
700 vi2 = result.AsClip()->GetVideoInfo();
701 if (!vi.IsSameColorspace(vi2)) {
702 error = "ScriptClip: Function did not return a video clip of the same colorspace as the source clip!";
703 } else if (vi2.width != vi.width) {
704 error = "ScriptClip: Function did not return a video clip with the same width as the source clip!";
705 } else if (vi2.height != vi.height) {
706 error = "ScriptClip: Function did not return a video clip with the same height as the source clip!";
707 }
708 }
709
710 if (error != NULL) {
711 PVideoFrame dst = child->GetFrame(n,env);
712 env->MakeWritable(&dst);
713 env->ApplyMessage(&dst, vi, error, vi.width/W_DIVISOR, 0xa0a0a0, 0, 0);
714 return dst;
715 }
716
717 n = min(n,vi2.num_frames-1); // We ignore it if the new clip is not as long as the current one. This can allow the resulting clip to be one frame.
718
719 return result.AsClip()->GetFrame(n,env);
720 }
721
722
723 AVSValue __cdecl ScriptClip::Create(AVSValue args, void* , IScriptEnvironment* env)
724 {
725 const bool runtime_local_default = args[1].IsFunction() ? true : false; // Avisynth compatibility: false, Neo: true. functions are legacy Neo
726
727 return new ScriptClip(args[0].AsClip(), args[1], args[2].AsBool(false),false, args[3].AsBool(false), args[4].AsBool(runtime_local_default), env);
728 }
729
730
731 AVSValue __cdecl ScriptClip::Create_eval(AVSValue args, void* , IScriptEnvironment* env)
732 {
733 const bool runtime_local_default = args[1].IsFunction() ? true : false; // Avisynth compatibility: false, Neo: true. functions are legacy Neo
734
735 return new ScriptClip(args[0].AsClip(), args[1], args[2].AsBool(false),true, args[3].AsBool(false), args[4].AsBool(runtime_local_default), env);}
736