GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 12.3% 107 / 0 / 867
Functions: 11.4% 4 / 0 / 35
Branches: 6.9% 119 / 0 / 1722

filters/conditional/conditional_functions.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_functions.h"
37 #include "../focus.h" // sad
38 #ifdef INTEL_INTRINSICS
39 #include "intel/conditional_functions_sse.h"
40 #include "../intel/focus_sse.h" // sad
41 #endif
42 #include "../../core/internal.h"
43 #include <avs/config.h>
44 #include <avs/minmax.h>
45 #include <avs/alignment.h>
46 #include <limits>
47 #include <algorithm>
48 #include <cmath>
49 #include "../core/AVSMap.h"
50
51 extern const AVSFunction Conditional_funtions_filters[] = {
52 { "AverageLuma", BUILTIN_FUNC_PREFIX, "c[offset]i", AveragePlane::Create, (void *)PLANAR_Y },
53 { "AverageChromaU", BUILTIN_FUNC_PREFIX, "c[offset]i", AveragePlane::Create, (void *)PLANAR_U },
54 { "AverageChromaV", BUILTIN_FUNC_PREFIX, "c[offset]i", AveragePlane::Create, (void *)PLANAR_V },
55 { "AverageR", BUILTIN_FUNC_PREFIX, "c[offset]i", AveragePlane::Create, (void *)PLANAR_R },
56 { "AverageG", BUILTIN_FUNC_PREFIX, "c[offset]i", AveragePlane::Create, (void *)PLANAR_G },
57 { "AverageB", BUILTIN_FUNC_PREFIX, "c[offset]i", AveragePlane::Create, (void *)PLANAR_B },
58 { "AverageA", BUILTIN_FUNC_PREFIX, "c[offset]i", AveragePlane::Create, (void *)PLANAR_A },
59 //{ "AverageSat","c[offset]i", AverageSat::Create }, Sum(SatLookup[U,V])/N, SatLookup[U,V]=1.4087*sqrt((U-128)**2+(V-128)**2)
60 //{ "AverageHue","c[offset]i", AverageHue::Create }, Sum(HueLookup[U,V])/N, HueLookup[U,V]=40.5845*Atan2(U-128,V-128)
61
62 { "RGBDifference", BUILTIN_FUNC_PREFIX, "cc", ComparePlane::Create, (void *)-1 },
63 { "LumaDifference", BUILTIN_FUNC_PREFIX, "cc", ComparePlane::Create, (void *)PLANAR_Y },
64 { "ChromaUDifference", BUILTIN_FUNC_PREFIX, "cc", ComparePlane::Create, (void *)PLANAR_U },
65 { "ChromaVDifference", BUILTIN_FUNC_PREFIX, "cc", ComparePlane::Create, (void *)PLANAR_V },
66 { "RDifference", BUILTIN_FUNC_PREFIX, "cc", ComparePlane::Create, (void *)PLANAR_R },
67 { "GDifference", BUILTIN_FUNC_PREFIX, "cc", ComparePlane::Create, (void *)PLANAR_G },
68 { "BDifference", BUILTIN_FUNC_PREFIX, "cc", ComparePlane::Create, (void *)PLANAR_B },
69 //{ "SatDifference","cc", CompareSat::Create }, Sum(Abs(SatLookup[U1,V1]-SatLookup[U2,V2]))/N
70 //{ "HueDifference","cc", CompareHue::Create }, Sum(Abs(HueLookup[U1,V1]-HueLookup[U2,V2]))/N
71
72 { "YDifferenceFromPrevious", BUILTIN_FUNC_PREFIX, "c", ComparePlane::Create_prev, (void *)PLANAR_Y },
73 { "UDifferenceFromPrevious", BUILTIN_FUNC_PREFIX, "c", ComparePlane::Create_prev, (void *)PLANAR_U },
74 { "VDifferenceFromPrevious", BUILTIN_FUNC_PREFIX, "c", ComparePlane::Create_prev, (void *)PLANAR_V },
75 { "RGBDifferenceFromPrevious", BUILTIN_FUNC_PREFIX, "c", ComparePlane::Create_prev, (void *)-1 },
76 { "RDifferenceFromPrevious", BUILTIN_FUNC_PREFIX, "c", ComparePlane::Create_prev, (void *)PLANAR_R },
77 { "GDifferenceFromPrevious", BUILTIN_FUNC_PREFIX, "c", ComparePlane::Create_prev, (void *)PLANAR_G },
78 { "BDifferenceFromPrevious", BUILTIN_FUNC_PREFIX, "c", ComparePlane::Create_prev, (void *)PLANAR_B },
79 //{ "SatDifferenceFromPrevious","c", CompareSat::Create_prev },
80 //{ "HueDifferenceFromPrevious","c", CompareHue::Create_prev },
81
82 { "YDifferenceToNext", BUILTIN_FUNC_PREFIX, "c[offset]i", ComparePlane::Create_next, (void *)PLANAR_Y },
83 { "UDifferenceToNext", BUILTIN_FUNC_PREFIX, "c[offset]i", ComparePlane::Create_next, (void *)PLANAR_U },
84 { "VDifferenceToNext", BUILTIN_FUNC_PREFIX, "c[offset]i", ComparePlane::Create_next, (void *)PLANAR_V },
85 { "RGBDifferenceToNext", BUILTIN_FUNC_PREFIX, "c[offset]i", ComparePlane::Create_next, (void *)-1 },
86 { "RDifferenceToNext", BUILTIN_FUNC_PREFIX, "c[offset]i", ComparePlane::Create_next, (void *)PLANAR_R },
87 { "GDifferenceToNext", BUILTIN_FUNC_PREFIX, "c[offset]i", ComparePlane::Create_next, (void *)PLANAR_G },
88 { "BDifferenceToNext", BUILTIN_FUNC_PREFIX, "c[offset]i", ComparePlane::Create_next, (void *)PLANAR_B },
89 //{ "SatDifferenceFromNext","c[offset]i", CompareSat::Create_next },
90 //{ "HueDifferenceFromNext","c[offset]i", CompareHue::Create_next },
91 { "PlaneMinMaxStats", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i[plane]i[setvar]b", MinMaxPlane::Create_minmax_stats, (void*)-1 },
92 { "YPlaneMax", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_max, (void *)PLANAR_Y },
93 { "YPlaneMin", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_min, (void *)PLANAR_Y },
94 { "YPlaneMedian", BUILTIN_FUNC_PREFIX, "c[offset]i", MinMaxPlane::Create_median, (void *)PLANAR_Y },
95 { "UPlaneMax", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_max, (void *)PLANAR_U },
96 { "UPlaneMin", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_min, (void *)PLANAR_U },
97 { "UPlaneMedian", BUILTIN_FUNC_PREFIX, "c[offset]i", MinMaxPlane::Create_median, (void *)PLANAR_U },
98 { "VPlaneMax", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_max, (void *)PLANAR_V }, // AVS+! was before: missing offset parameter
99 { "VPlaneMin", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_min, (void *)PLANAR_V }, // AVS+! was before: missing offset parameter
100 { "VPlaneMedian", BUILTIN_FUNC_PREFIX, "c[offset]i", MinMaxPlane::Create_median, (void *)PLANAR_V },
101 { "RPlaneMax", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_max, (void *)PLANAR_R },
102 { "RPlaneMin", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_min, (void *)PLANAR_R },
103 { "RPlaneMedian", BUILTIN_FUNC_PREFIX, "c[offset]i", MinMaxPlane::Create_median, (void *)PLANAR_R },
104 { "GPlaneMax", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_max, (void *)PLANAR_G },
105 { "GPlaneMin", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_min, (void *)PLANAR_G },
106 { "GPlaneMedian", BUILTIN_FUNC_PREFIX, "c[offset]i", MinMaxPlane::Create_median, (void *)PLANAR_G },
107 { "BPlaneMax", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_max, (void *)PLANAR_B },
108 { "BPlaneMin", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_min, (void *)PLANAR_B },
109 { "BPlaneMedian", BUILTIN_FUNC_PREFIX, "c[offset]i", MinMaxPlane::Create_median, (void *)PLANAR_B },
110 { "YPlaneMinMaxDifference", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_minmax, (void *)PLANAR_Y },
111 { "UPlaneMinMaxDifference", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_minmax, (void *)PLANAR_U }, // AVS+! was before: missing offset parameter
112 { "VPlaneMinMaxDifference", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_minmax, (void *)PLANAR_V }, // AVS+! was before: missing offset parameter
113 { "RPlaneMinMaxDifference", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_minmax, (void *)PLANAR_R },
114 { "GPlaneMinMaxDifference", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_minmax, (void *)PLANAR_G },
115 { "BPlaneMinMaxDifference", BUILTIN_FUNC_PREFIX, "c[threshold]f[offset]i", MinMaxPlane::Create_minmax, (void *)PLANAR_B },
116
117 //{ "SatMax","c[threshold]f[offset]i", MinMaxPlane::Create_maxsat }, ++accum[SatLookup[U,V]]
118 //{ "SatMin","c[threshold]f[offset]i", MinMaxPlane::Create_minsat },
119 //{ "SatMedian","c[offset]i", MinMaxPlane::Create_mediansat },
120 //{ "SatMinMaxDifference","c[threshold]f[offset]i", MinMaxPlane::Create_minmaxsat },
121
122 //{ "HueMax","c[threshold]f[offset]i", MinMaxPlane::Create_maxhue }, ++accum[HueLookup[U,V]]
123 //{ "HueMin","c[threshold]f[offset]i", MinMaxPlane::Create_minhue },
124 //{ "HueMedian","c[offset]i", MinMaxPlane::Create_medianhue },
125 //{ "HueMinMaxDifference","c[threshold]f[offset]i", MinMaxPlane::Create_minmaxhue },
126
127 // frame property setters in conditional_reader
128 { "propGetAny", BUILTIN_FUNC_PREFIX, "cs[index]i[offset]i", GetProperty::Create, (void*)0 },
129 { "propGetInt", BUILTIN_FUNC_PREFIX, "cs[index]i[offset]i", GetProperty::Create, (void *)1 },
130 { "propGetFloat", BUILTIN_FUNC_PREFIX, "cs[index]i[offset]i", GetProperty::Create, (void*)2 },
131 { "propGetString", BUILTIN_FUNC_PREFIX, "cs[index]i[offset]i", GetProperty::Create, (void*)3 },
132 { "propGetClip", BUILTIN_FUNC_PREFIX, "cs[index]i[offset]i", GetProperty::Create, (void*)4 },
133 { "propGetDataSize", BUILTIN_FUNC_PREFIX, "cs[index]i[offset]i", GetPropertyDataSize::Create },
134 { "propNumElements", BUILTIN_FUNC_PREFIX, "cs[offset]i", GetPropertyNumElements::Create},
135 { "propNumKeys", BUILTIN_FUNC_PREFIX, "c[offset]i", GetPropertyNumKeys::Create},
136 { "propGetKeyByIndex", BUILTIN_FUNC_PREFIX, "c[index]i[offset]i", GetPropertyKeyByIndex::Create},
137 { "propGetType", BUILTIN_FUNC_PREFIX, "cs[offset]i", GetPropertyType::Create},
138 { "propGetAsArray", BUILTIN_FUNC_PREFIX, "cs[offset]i", GetPropertyAsArray::Create},
139 { "propGetAll", BUILTIN_FUNC_PREFIX, "c[offset]i", GetAllProperties::Create},
140
141 { 0 }
142 };
143
144
145 AVSValue AveragePlane::Create(AVSValue args, void* user_data, IScriptEnvironment* env) {
146 int plane = (int)reinterpret_cast<intptr_t>(user_data);
147 return AvgPlane(args[0], user_data, plane, args[1].AsInt(0), env);
148 }
149
150 // Average plane
151 template<typename pixel_t>
152 static double get_sum_of_pixels_c(const BYTE* srcp8, size_t height, size_t width, size_t pitch) {
153 typedef typename std::conditional < sizeof(pixel_t) == 4, double, int64_t>::type sum_t;
154 sum_t accum = 0; // int32 holds sum of maximum 16 Mpixels for 8 bit, and 65536 pixels for uint16_t pixels
155 const pixel_t *srcp = reinterpret_cast<const pixel_t *>(srcp8);
156 pitch /= sizeof(pixel_t);
157 for (size_t y = 0; y < height; y++) {
158 for (size_t x = 0; x < width; x++) {
159 accum += srcp[x];
160 }
161 srcp += pitch;
162 }
163 return (double)accum;
164 }
165
166 AVSValue AveragePlane::AvgPlane(AVSValue clip, void* , int plane, int offset, IScriptEnvironment* env)
167 {
168 if (!clip.IsClip())
169 env->ThrowError("Average Plane: No clip supplied!");
170
171 PClip child = clip.AsClip();
172 VideoInfo vi = child->GetVideoInfo();
173
174 // input clip to always planar
175 if (vi.IsRGB() && !vi.IsPlanar()) {
176 AVSValue new_args[1] = { child };
177 if (vi.IsRGB24() || vi.IsRGB48())
178 child = env->Invoke("ConvertToPlanarRGB", AVSValue(new_args, 1)).AsClip();
179 else // RGB32, RGB64
180 child = env->Invoke("ConvertToPlanarRGBA", AVSValue(new_args, 1)).AsClip();
181 vi = child->GetVideoInfo();
182 }
183 else if (vi.IsYUY2()) {
184 AVSValue new_args[2] = { child, false };
185 child = env->Invoke("ConvertToYUV422", AVSValue(new_args, 2)).AsClip();
186 vi = child->GetVideoInfo();
187 }
188
189 if (!vi.IsPlanar())
190 env->ThrowError("Average Plane: Only planar YUV or planar RGB images supported!");
191
192 if (plane == PLANAR_A)
193 {
194 if (!vi.IsPlanarRGBA() && !vi.IsYUVA())
195 env->ThrowError("Average Plane: clip has no Alpha plane!");
196 }
197 else if(vi.IsRGB())
198 {
199 if (plane != PLANAR_R && plane != PLANAR_G && plane != PLANAR_B)
200 env->ThrowError("Average Plane: not a valid plane for an RGB clip!");
201 }
202 else if (vi.IsY()){
203 if (plane != PLANAR_Y)
204 env->ThrowError("Average Plane: not a valid plane for an greyscale clip!");
205 }
206 else {
207 if (plane != PLANAR_Y && plane != PLANAR_U && plane != PLANAR_V)
208 env->ThrowError("Average Plane: not a valid plane for a YUV clip!");
209 }
210
211 AVSValue cn = env->GetVarDef("current_frame");
212 if (!cn.IsInt())
213 env->ThrowError("Average Plane: This filter can only be used within run-time filters");
214
215 int n = cn.AsInt();
216 n = min(max(n+offset,0), vi.num_frames-1);
217
218 PVideoFrame src = child->GetFrame(n,env);
219
220 int pixelsize = vi.ComponentSize();
221
222 const BYTE* srcp = src->GetReadPtr(plane);
223 int height = src->GetHeight(plane);
224 int width = src->GetRowSize(plane) / pixelsize;
225 int pitch = src->GetPitch(plane);
226
227 if (width == 0 || height == 0)
228 env->ThrowError("Average Plane: plane does not exist!");
229
230 double sum = 0.0;
231
232
233 int total_pixels = width*height;
234 bool sum_in_32bits;
235 if (pixelsize == 4)
236 sum_in_32bits = false;
237 else // worst case
238 sum_in_32bits = ((int64_t)total_pixels * (pixelsize == 1 ? 255 : 65535)) <= std::numeric_limits<int>::max();
239
240 #ifdef INTEL_INTRINSICS
241 if ((pixelsize==1) && sum_in_32bits && (env->GetCPUFlags() & CPUF_SSE2) && width >= 16) {
242 sum = get_sum_of_pixels_sse2(srcp, height, width, pitch);
243 } else
244 #ifdef X86_32
245 if ((pixelsize==1) && sum_in_32bits && (env->GetCPUFlags() & CPUF_INTEGER_SSE) && width >= 8) {
246 sum = get_sum_of_pixels_isse(srcp, height, width, pitch);
247 } else
248 #endif
249 #endif
250 {
251 if(pixelsize==1)
252 sum = get_sum_of_pixels_c<uint8_t>(srcp, height, width, pitch);
253 else if(pixelsize==2)
254 sum = get_sum_of_pixels_c<uint16_t>(srcp, height, width, pitch);
255 else // pixelsize==4
256 sum = get_sum_of_pixels_c<float>(srcp, height, width, pitch);
257 }
258
259 float f = (float)(sum / (height * width));
260
261 return (AVSValue)f;
262 }
263
264 AVSValue ComparePlane::Create(AVSValue args, void* user_data, IScriptEnvironment* env) {
265 int plane = (int)reinterpret_cast<intptr_t>(user_data);
266 return CmpPlane(args[0],args[1], user_data, plane, env);
267 }
268
269 AVSValue ComparePlane::Create_prev(AVSValue args, void* user_data, IScriptEnvironment* env) {
270 int plane = (int)reinterpret_cast<intptr_t>(user_data);
271 return CmpPlaneSame(args[0], user_data, -1, plane, env);
272 }
273
274 AVSValue ComparePlane::Create_next(AVSValue args, void* user_data, IScriptEnvironment* env) {
275 int plane = (int)reinterpret_cast<intptr_t>(user_data);
276 return CmpPlaneSame(args[0], user_data, args[1].AsInt(1), plane, env);
277 }
278
279
280 template<typename pixel_t>
281 static double get_sad_c(const BYTE* c_plane8, const BYTE* t_plane8, size_t height, size_t width, size_t c_pitch, size_t t_pitch) {
282 const pixel_t *c_plane = reinterpret_cast<const pixel_t *>(c_plane8);
283 const pixel_t *t_plane = reinterpret_cast<const pixel_t *>(t_plane8);
284 c_pitch /= sizeof(pixel_t);
285 t_pitch /= sizeof(pixel_t);
286 typedef typename std::conditional < sizeof(pixel_t) == 4, double, int64_t>::type sum_t;
287 sum_t accum = 0; // int32 holds sum of maximum 16 Mpixels for 8 bit, and 65536 pixels for uint16_t pixels
288
289 for (size_t y = 0; y < height; y++) {
290 for (size_t x = 0; x < width; x++) {
291 accum += std::abs(t_plane[x] - c_plane[x]);
292 }
293 c_plane += c_pitch;
294 t_plane += t_pitch;
295 }
296 return (double)accum;
297
298 }
299
300 template<typename pixel_t>
301 static double get_sad_rgb_c(const BYTE* c_plane8, const BYTE* t_plane8, size_t height, size_t width, size_t c_pitch, size_t t_pitch) {
302 const pixel_t *c_plane = reinterpret_cast<const pixel_t *>(c_plane8);
303 const pixel_t *t_plane = reinterpret_cast<const pixel_t *>(t_plane8);
304 c_pitch /= sizeof(pixel_t);
305 t_pitch /= sizeof(pixel_t);
306 int64_t accum = 0; // packed rgb: integer type only
307 for (size_t y = 0; y < height; y++) {
308 for (size_t x = 0; x < width; x+=4) {
309 accum += std::abs(t_plane[x] - c_plane[x]);
310 accum += std::abs(t_plane[x+1] - c_plane[x+1]);
311 accum += std::abs(t_plane[x+2] - c_plane[x+2]);
312 }
313 c_plane += c_pitch;
314 t_plane += t_pitch;
315 }
316 return (double)accum;
317
318 }
319
320 1 AVSValue ComparePlane::CmpPlane(AVSValue clip, AVSValue clip2, void* , int plane, IScriptEnvironment* env)
321 {
322
2/4
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 167 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
1 if (!clip.IsClip())
323 env->ThrowError("Plane Difference: No clip supplied!");
324
2/4
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 167 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 1 time.
1 if (!clip2.IsClip())
325 env->ThrowError("Plane Difference: Second parameter is not a clip!");
326
327
1/2
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 167 not taken.
1 PClip child = clip.AsClip();
328
1/2
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 165 not taken.
1 VideoInfo vi = child->GetVideoInfo();
329
1/2
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 165 not taken.
1 PClip child2 = clip2.AsClip();
330
1/2
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 163 not taken.
1 VideoInfo vi2 = child2->GetVideoInfo();
331
1/2
✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 23 not taken.
1 if (plane !=-1 ) {
332
5/10
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 163 not taken.
✓ Branch 16 → 17 taken 1 time.
✗ Branch 16 → 19 not taken.
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 163 not taken.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 1 time.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 46 taken 1 time.
1 if (!vi.IsPlanar() || !vi2.IsPlanar())
333 env->ThrowError("Plane Difference: Only planar YUV or planar RGB images supported!");
334 } else {
335 if(vi.IsPlanarRGB() || vi.IsPlanarRGBA())
336 env->ThrowError("RGB Difference: Planar RGB is not supported here (clip 1)");
337 if(vi2.IsPlanarRGB() || vi2.IsPlanarRGBA())
338 env->ThrowError("RGB Difference: Planar RGB is not supported here (clip 2)");
339 if (!vi.IsRGB())
340 env->ThrowError("RGB Difference: RGB difference can only be tested on RGB images! (clip 1)");
341 if (!vi2.IsRGB())
342 env->ThrowError("RGB Difference: RGB difference can only be tested on RGB images! (clip 2)");
343 plane = 0;
344 }
345
346
2/4
✓ Branch 46 → 47 taken 1 time.
✗ Branch 46 → 156 not taken.
✓ Branch 47 → 48 taken 1 time.
✗ Branch 47 → 154 not taken.
1 AVSValue cn = env->GetVarDef("current_frame");
347
2/4
✓ Branch 49 → 50 taken 1 time.
✗ Branch 49 → 161 not taken.
✗ Branch 50 → 51 not taken.
✓ Branch 50 → 52 taken 1 time.
1 if (!cn.IsInt())
348 env->ThrowError("Plane Difference: This filter can only be used within run-time filters");
349
350
1/2
✓ Branch 52 → 53 taken 1 time.
✗ Branch 52 → 161 not taken.
1 int n = cn.AsInt();
351 1 n = clamp(n,0,vi.num_frames-1);
352
353
1/2
✓ Branch 55 → 56 taken 1 time.
✗ Branch 55 → 161 not taken.
1 PVideoFrame src = child->GetFrame(n,env);
354
1/2
✗ Branch 57 → 58 not taken.
✓ Branch 57 → 159 taken 1 time.
1 PVideoFrame src2 = child2->GetFrame(n,env);
355
356 int pixelsize = vi.ComponentSize();
357
358 const BYTE* srcp = src->GetReadPtr(plane);
359 const BYTE* srcp2 = src2->GetReadPtr(plane);
360 const int height = src->GetHeight(plane);
361 const int rowsize = src->GetRowSize(plane);
362 const int width = rowsize / pixelsize;
363 const int pitch = src->GetPitch(plane);
364 const int height2 = src2->GetHeight(plane);
365 const int rowsize2 = src2->GetRowSize(plane);
366 const int width2 = rowsize2 / pixelsize;
367 const int pitch2 = src2->GetPitch(plane);
368
369 if(vi.ComponentSize() != vi2.ComponentSize())
370 env->ThrowError("Plane Difference: Bit-depth are not the same!");
371
372 if (width == 0 || height == 0)
373 env->ThrowError("Plane Difference: plane does not exist!");
374
375 if (height != height2 || width != width2)
376 env->ThrowError("Plane Difference: Images are not the same size!");
377
378 #ifdef X86_32
379 int bits_per_pixel = vi.BitsPerComponent();
380 int total_pixels = width*height;
381 bool sum_in_32bits;
382 if (pixelsize == 4)
383 sum_in_32bits = false;
384 else // worst case check
385 sum_in_32bits = ((int64_t)total_pixels * ((1 << bits_per_pixel) - 1)) <= std::numeric_limits<int>::max();
386 #endif
387
388 double sad = 0.0;
389
390 // for c: width, for sse: rowsize
391 if (vi.IsRGB32() || vi.IsRGB64()) {
392 #ifdef INTEL_INTRINSICS
393 if ((pixelsize == 2) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) {
394 // int64 internally, no sum_in_32bits
395 sad = (double)calculate_sad_8_or_16_sse2<uint16_t,true>(srcp, srcp2, pitch, pitch2, width*pixelsize, height); // in focus. 21.68/21.39
396 } else if ((pixelsize == 1) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) {
397 sad = (double)calculate_sad_8_or_16_sse2<uint8_t,true>(srcp, srcp2, pitch, pitch2, rowsize, height); // in focus, no overflow
398 } else
399 #ifdef X86_32
400 if ((pixelsize==1) && sum_in_32bits && (env->GetCPUFlags() & CPUF_INTEGER_SSE) && width >= 8) {
401 sad = get_sad_rgb_isse(srcp, srcp2, height, rowsize, pitch, pitch2);
402 } else
403 #endif
404 #endif
405 {
406 if (pixelsize == 1)
407 sad = (double)get_sad_rgb_c<uint8_t>(srcp, srcp2, height, width, pitch, pitch2);
408 else // pixelsize==2
409 sad = (double)get_sad_rgb_c<uint16_t>(srcp, srcp2, height, width, pitch, pitch2);
410 }
411 } else {
412 #ifdef INTEL_INTRINSICS
413 if ((pixelsize==2) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) {
414 sad = (double)calculate_sad_8_or_16_sse2<uint16_t,false>(srcp, srcp2, pitch, pitch2, rowsize, height); // in focus, no overflow
415 } else
416 if ((pixelsize==1) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) {
417 sad = (double)calculate_sad_8_or_16_sse2<uint8_t,false>(srcp, srcp2, pitch, pitch2, rowsize, height); // in focus, no overflow
418 } else
419 #ifdef X86_32
420 if ((pixelsize==1) && sum_in_32bits && (env->GetCPUFlags() & CPUF_INTEGER_SSE) && width >= 8) {
421 sad = get_sad_isse(srcp, srcp2, height, rowsize, pitch, pitch2);
422 } else
423 #endif
424 #endif
425 {
426 if(pixelsize==1)
427 sad = get_sad_c<uint8_t>(srcp, srcp2, height, width, pitch, pitch2);
428 else if(pixelsize==2)
429 sad = get_sad_c<uint16_t>(srcp, srcp2, height, width, pitch, pitch2);
430 else // pixelsize==4
431 sad = get_sad_c<float>(srcp, srcp2, height, width, pitch, pitch2);
432 }
433 }
434
435 float f;
436
437 if (vi.IsRGB32() || vi.IsRGB64())
438 f = (float)((sad * 4) / (height * width * 3)); // why * 4/3? alpha plane was masked out, anyway
439 else
440 f = (float)(sad / (height * width));
441
442 return (AVSValue)f;
443 4 }
444
445
446 AVSValue ComparePlane::CmpPlaneSame(AVSValue clip, void* , int offset, int plane, IScriptEnvironment* env)
447 {
448 if (!clip.IsClip())
449 env->ThrowError("Plane Difference: No clip supplied!");
450
451 PClip child = clip.AsClip();
452 VideoInfo vi = child->GetVideoInfo();
453 if (plane ==-1 ) {
454 if (!vi.IsRGB() || vi.IsPlanarRGB() || vi.IsPlanarRGBA())
455 env->ThrowError("RGB Difference: RGB difference can only be calculated on packed RGB images");
456 plane = 0;
457 } else {
458 if (!vi.IsPlanar())
459 env->ThrowError("Plane Difference: Only planar YUV or planar RGB images images supported!");
460 }
461
462 AVSValue cn = env->GetVarDef("current_frame");
463 if (!cn.IsInt())
464 env->ThrowError("Plane Difference: This filter can only be used within run-time filters");
465
466 int n = cn.AsInt();
467 n = clamp(n,0,vi.num_frames-1);
468 int n2 = clamp(n+offset,0,vi.num_frames-1);
469
470 PVideoFrame src = child->GetFrame(n,env);
471 PVideoFrame src2 = child->GetFrame(n2,env);
472
473 int pixelsize = vi.ComponentSize();
474
475 const BYTE* srcp = src->GetReadPtr(plane);
476 const BYTE* srcp2 = src2->GetReadPtr(plane);
477 int height = src->GetHeight(plane);
478 int rowsize = src->GetRowSize(plane);
479 int width = rowsize / pixelsize;
480 int pitch = src->GetPitch(plane);
481 int pitch2 = src2->GetPitch(plane);
482
483 if (width == 0 || height == 0)
484 env->ThrowError("Plane Difference: No chroma planes in greyscale clip!");
485
486 #ifdef X86_32
487 int bits_per_pixel = vi.BitsPerComponent();
488 int total_pixels = width * height;
489 bool sum_in_32bits;
490 if (pixelsize == 4)
491 sum_in_32bits = false;
492 else // worst case check
493 sum_in_32bits = ((int64_t)total_pixels * ((1 << bits_per_pixel) - 1)) <= std::numeric_limits<int>::max();
494 #endif
495
496 double sad = 0;
497 // for c: width, for sse: rowsize
498 if (vi.IsRGB32() || vi.IsRGB64()) {
499 #ifdef INTEL_INTRINSICS
500 if ((pixelsize == 2) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) {
501 // int64 internally, no sum_in_32bits
502 sad = (double)calculate_sad_8_or_16_sse2<uint16_t,true>(srcp, srcp2, pitch, pitch2, rowsize, height); // in focus. 21.68/21.39
503 } else if ((pixelsize == 1) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) {
504 sad = (double)calculate_sad_8_or_16_sse2<uint8_t,true>(srcp, srcp2, pitch, pitch2, rowsize, height); // in focus, no overflow
505 } else
506 #ifdef X86_32
507 if ((pixelsize==1) && sum_in_32bits && (env->GetCPUFlags() & CPUF_INTEGER_SSE) && width >= 8) {
508 sad = get_sad_rgb_isse(srcp, srcp2, height, rowsize, pitch, pitch2);
509 } else
510 #endif
511 #endif
512 {
513 if(pixelsize==1)
514 sad = get_sad_rgb_c<uint8_t>(srcp, srcp2, height, width, pitch, pitch2);
515 else
516 sad = get_sad_rgb_c<uint16_t>(srcp, srcp2, height, width, pitch, pitch2);
517 }
518 } else {
519 #ifdef INTEL_INTRINSICS
520 if ((pixelsize==2) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) {
521 sad = (double)calculate_sad_8_or_16_sse2<uint16_t,false>(srcp, srcp2, pitch, pitch2, rowsize, height); // in focus, no overflow
522 } else if ((pixelsize==1) && (env->GetCPUFlags() & CPUF_SSE2) && rowsize >= 16) {
523 sad = (double)calculate_sad_8_or_16_sse2<uint8_t,false>(srcp, srcp2, pitch, pitch2, rowsize, height); // in focus, no overflow
524 } else
525 #ifdef X86_32
526 if ((pixelsize==1) && sum_in_32bits && (env->GetCPUFlags() & CPUF_INTEGER_SSE) && width >= 8) {
527 sad = get_sad_isse(srcp, srcp2, height, width, pitch, pitch2);
528 } else
529 #endif
530 #endif
531 {
532 if(pixelsize==1)
533 sad = get_sad_c<uint8_t>(srcp, srcp2, height, width, pitch, pitch2);
534 else if (pixelsize==2)
535 sad = get_sad_c<uint16_t>(srcp, srcp2, height, width, pitch, pitch2);
536 else // pixelsize==4
537 sad = get_sad_c<float>(srcp, srcp2, height, width, pitch, pitch2);
538 }
539 }
540
541 float f;
542
543 if (vi.IsRGB32() || vi.IsRGB64())
544 f = (float)((sad * 4) / (height * width * 3));
545 else
546 f = (float)(sad / (height * width));
547
548 return (AVSValue)f;
549 }
550
551 AVSValue MinMaxPlane::Create_minmax_stats(AVSValue args, void* user_data, IScriptEnvironment* env) {
552 const int plane = args[3].AsInt(0); // 0:Y or R 1:U or G 2: V or B 3:A
553 if (plane < 0 || plane>3)
554 env->ThrowError("MinMax Stats: plane index must be between 0-3!");
555
556 if (!args[0].IsClip())
557 env->ThrowError("MinMax Stats: No clip supplied!");
558
559 VideoInfo vi = args[0].AsClip()->GetVideoInfo();
560 const int planes_y[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A };
561 const int planes_r[4] = { PLANAR_R, PLANAR_G, PLANAR_B, PLANAR_A }; // in 'logical' RGB order
562 const int* planes = (vi.IsYUV() || vi.IsYUVA()) ? planes_y : planes_r;
563
564 const int current_plane = planes[plane];
565
566 const int setvar = args[4].AsBool(false);
567
568 return MinMax(args[0], user_data, args[1].AsDblDef(0.0), args[2].AsInt(0), current_plane, MinMaxPlane::STATS, setvar, env);
569 }
570
571
572 1 AVSValue MinMaxPlane::Create_max(AVSValue args, void* user_data, IScriptEnvironment* env) {
573 1 int plane = (int)reinterpret_cast<intptr_t>(user_data);
574
3/6
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 15 not taken.
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 15 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 13 not taken.
1 return MinMax(args[0], user_data, args[1].AsDblDef(0.0), args[2].AsInt(0), plane, MinMaxPlane::MAX, false, env);
575 }
576
577 AVSValue MinMaxPlane::Create_min(AVSValue args, void* user_data, IScriptEnvironment* env) {
578 int plane = (int)reinterpret_cast<intptr_t>(user_data);
579 return MinMax(args[0], user_data, args[1].AsDblDef(0.0), args[2].AsInt(0), plane, MinMaxPlane::MIN, false, env);
580 }
581
582 AVSValue MinMaxPlane::Create_median(AVSValue args, void* user_data, IScriptEnvironment* env) {
583 int plane = (int)reinterpret_cast<intptr_t>(user_data);
584 // MEDIAN: min 50%
585 return MinMax(args[0], user_data, 50.0, args[1].AsInt(0), plane, MinMaxPlane::MIN, false, env);
586 }
587
588 AVSValue MinMaxPlane::Create_minmax(AVSValue args, void* user_data, IScriptEnvironment* env) {
589 int plane = (int)reinterpret_cast<intptr_t>(user_data);
590 return MinMax(args[0], user_data, args[1].AsDblDef(0.0), args[2].AsInt(0), plane, MinMaxPlane::MINMAX_DIFFERENCE, false, env);
591 }
592
593 template<bool average>
594 void get_minmax_float_c(const BYTE* srcp, int pitch, int w, int h, float& min, float& max, double &sum)
595 {
596 min = *reinterpret_cast<const float*>(srcp);
597 max = min;
598 sum = 0;
599
600 for (int y = 0; y < h; y++) {
601 for (int x = 0; x < w; x++) {
602 const float pix = reinterpret_cast<const float*>(srcp)[x];
603 if constexpr(average)
604 sum += pix;
605 if (pix < min) min = pix;
606 if (pix > max) max = pix;
607 }
608 srcp += pitch;
609 }
610 }
611
612 template<typename pixel_t, bool average>
613 void get_minmax_int_c(const BYTE* srcp, int pitch, int w, int h, int& min, int& max, int64_t& sum)
614 {
615 min = *reinterpret_cast<const pixel_t*>(srcp);
616 max = min;
617 sum = 0;
618
619 for (int y = 0; y < h; y++) {
620 int tmpsum = 0;
621 for (int x = 0; x < w; x++) {
622 const int pix = reinterpret_cast<const pixel_t*>(srcp)[x];
623 if constexpr (average)
624 sum += pix;
625 if (pix < min) min = pix;
626 if (pix > max) max = pix;
627 }
628 if constexpr (average)
629 sum += tmpsum;
630 srcp += pitch;
631 }
632 }
633
634 1 AVSValue MinMaxPlane::MinMax(AVSValue clip, void* , double threshold, int offset, int plane, int mode, bool setvar, IScriptEnvironment* env) {
635
636
2/4
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 404 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
1 if (!clip.IsClip())
637 env->ThrowError("MinMax: No clip supplied!");
638
639
1/2
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 404 not taken.
1 PClip child = clip.AsClip();
640
1/2
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 402 not taken.
1 VideoInfo vi = child->GetVideoInfo();
641
642
2/4
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 402 not taken.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 14 taken 1 time.
1 if (vi.IsRGB()) {
643 if (plane == PLANAR_Y || plane == PLANAR_U || plane == PLANAR_V)
644 env->ThrowError("MinMax: no such plane in RGB format");
645 }
646
2/4
✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 402 not taken.
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 18 not taken.
1 else if (vi.IsY()) {
647
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 22 taken 1 time.
1 if (plane != PLANAR_Y)
648 env->ThrowError("MinMax: no such plane in Y (greyscale) format");
649 }
650 else {
651 if (plane == PLANAR_R || plane == PLANAR_G || plane == PLANAR_B)
652 env->ThrowError("MinMax: no such plane in YUV format");
653 }
654
4/8
✓ Branch 22 → 23 taken 1 time.
✗ Branch 22 → 402 not taken.
✓ Branch 23 → 24 taken 1 time.
✗ Branch 23 → 26 not taken.
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 1 time.
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 1 time.
1 if (vi.NumComponents() < 4 && plane == PLANAR_A)
655 env->ThrowError("MinMax: no Alpha plane in this format");
656
657 // input clip to always planar
658
3/10
✓ Branch 29 → 30 taken 1 time.
✗ Branch 29 → 402 not taken.
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 34 taken 1 time.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 402 not taken.
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 34 not taken.
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 69 taken 1 time.
1 if (vi.IsRGB() && !vi.IsPlanar()) {
659 AVSValue new_args[1] = { child };
660 if (vi.IsRGB24() || vi.IsRGB48())
661 child = env->Invoke("ConvertToPlanarRGB", AVSValue(new_args, 1)).AsClip();
662 else // RGB32, RGB64
663 child = env->Invoke("ConvertToPlanarRGBA", AVSValue(new_args, 1)).AsClip();
664 vi = child->GetVideoInfo();
665 }
666
2/4
✓ Branch 69 → 70 taken 1 time.
✗ Branch 69 → 402 not taken.
✗ Branch 70 → 71 not taken.
✓ Branch 70 → 89 taken 1 time.
1 else if (vi.IsYUY2()) {
667 AVSValue new_args[2] = { child, false };
668 child = env->Invoke("ConvertToYUV422", AVSValue(new_args, 2)).AsClip();
669 vi = child->GetVideoInfo();
670 }
671
672
2/4
✓ Branch 89 → 90 taken 1 time.
✗ Branch 89 → 402 not taken.
✗ Branch 90 → 91 not taken.
✓ Branch 90 → 92 taken 1 time.
1 if (!vi.IsPlanar())
673 env->ThrowError("MinMax: Image must be planar");
674
675 // Get current frame number
676
2/4
✓ Branch 92 → 93 taken 1 time.
✗ Branch 92 → 362 not taken.
✓ Branch 93 → 94 taken 1 time.
✗ Branch 93 → 360 not taken.
1 AVSValue cn = env->GetVarDef("current_frame");
677
2/4
✓ Branch 95 → 96 taken 1 time.
✗ Branch 95 → 400 not taken.
✗ Branch 96 → 97 not taken.
✓ Branch 96 → 98 taken 1 time.
1 if (!cn.IsInt())
678 env->ThrowError("MinMax: This filter can only be used within run-time filters");
679
680
1/2
✓ Branch 98 → 99 taken 1 time.
✗ Branch 98 → 400 not taken.
1 int n = cn.AsInt();
681 1 n = min(max(n + offset, 0), vi.num_frames - 1);
682
683 // Prepare the source
684
1/2
✓ Branch 102 → 103 taken 1 time.
✗ Branch 102 → 400 not taken.
1 PVideoFrame src = child->GetFrame(n, env);
685
686
1/2
✓ Branch 104 → 105 taken 1 time.
✗ Branch 104 → 398 not taken.
1 const BYTE* srcp = src->GetReadPtr(plane);
687
1/2
✓ Branch 106 → 107 taken 1 time.
✗ Branch 106 → 398 not taken.
1 int pitch = src->GetPitch(plane);
688
1/2
✓ Branch 107 → 108 taken 1 time.
✗ Branch 107 → 398 not taken.
1 int pixelsize = vi.ComponentSize();
689
1/2
✓ Branch 109 → 110 taken 1 time.
✗ Branch 109 → 398 not taken.
1 int w = src->GetRowSize(plane) / pixelsize; // good for packed rgb as well
690
1/2
✓ Branch 111 → 112 taken 1 time.
✗ Branch 111 → 398 not taken.
1 int h = src->GetHeight(plane);
691
692
2/4
✓ Branch 112 → 113 taken 1 time.
✗ Branch 112 → 114 not taken.
✗ Branch 113 → 114 not taken.
✓ Branch 113 → 115 taken 1 time.
1 if (w == 0 || h == 0)
693 env->ThrowError("MinMax: plane does not exist!");
694
695 float stats_min;
696 float stats_max;
697 float stats_median;
698 float stats_thresholded_min;
699 float stats_thresholded_max;
700 float stats_average;
701
702
2/4
✓ Branch 115 → 116 taken 1 time.
✗ Branch 115 → 117 not taken.
✗ Branch 116 → 117 not taken.
✓ Branch 116 → 150 taken 1 time.
1 if (threshold == 0 || mode == MinMaxPlane::STATS) {
703 // special case, no histogram needed
704
705 if (pixelsize == 4) // 32 bit float
706 {
707 double sum = 0;
708 if (mode == MinMaxPlane::STATS)
709 get_minmax_float_c<true>(srcp, pitch, w, h, stats_min, stats_max, sum);
710 else
711 get_minmax_float_c<false>(srcp, pitch, w, h, stats_min, stats_max, sum);
712
713 if (mode == MinMaxPlane::MIN) return stats_min;
714 else if (mode == MinMaxPlane::MAX) return stats_max;
715 else if (mode == MinMaxPlane::MINMAX_DIFFERENCE) return stats_max - stats_min;
716 stats_average = (float)(sum / (w * h));
717 // STATS: go on
718 }
719 else
720 {
721 int min, max;
722 int64_t sum = 0;
723 // sse4.1 is not any faster
724 if(pixelsize == 1)
725 if (mode == MinMaxPlane::STATS)
726 get_minmax_int_c<uint8_t, true>(srcp, pitch, w, h, min, max, sum);
727 else
728 get_minmax_int_c<uint8_t, false>(srcp, pitch, w, h, min, max, sum);
729 else
730 if (mode == MinMaxPlane::STATS)
731 get_minmax_int_c<uint16_t, true>(srcp, pitch, w, h, min, max, sum);
732 else
733 get_minmax_int_c<uint16_t, false>(srcp, pitch, w, h, min, max, sum);
734
735 if (mode == MinMaxPlane::MIN) return min;
736 else if (mode == MinMaxPlane::MAX) return max;
737 else if (mode == MinMaxPlane::MINMAX_DIFFERENCE) return max - min;
738
739 // STATS: go on
740 stats_min = (float)min;
741 stats_max = (float)max;
742 stats_average = (float)((double)sum / (w * h));
743 }
744 }
745
746
1/2
✓ Branch 150 → 151 taken 1 time.
✗ Branch 150 → 398 not taken.
1 const int bits_per_pixel = vi.BitsPerComponent();
747 1 const int max_pixel_value = (1 << bits_per_pixel) - 1;
748
749
1/2
✓ Branch 151 → 152 taken 1 time.
✗ Branch 151 → 153 not taken.
1 const int buffersize = pixelsize == 4 ? 65536 : (1 << bits_per_pixel); // 65536 for float, too, reason for 10-14 bits: avoid overflow
750
2/4
✓ Branch 154 → 155 taken 1 time.
✗ Branch 154 → 156 not taken.
✓ Branch 157 → 158 taken 1 time.
✗ Branch 157 → 398 not taken.
1 uint32_t* accum_buf = new uint32_t[buffersize];
751
752 // Reset accumulators
753 1 std::fill_n(accum_buf, buffersize, 0);
754
755 // Count each component
756
1/2
✓ Branch 167 → 168 taken 1 time.
✗ Branch 167 → 174 not taken.
1 if (pixelsize == 1) {
757
2/2
✓ Branch 173 → 169 taken 2 times.
✓ Branch 173 → 201 taken 1 time.
3 for (int y = 0; y < h; y++) {
758
2/2
✓ Branch 171 → 170 taken 8 times.
✓ Branch 171 → 172 taken 2 times.
10 for (int x = 0; x < w; x++) {
759 8 accum_buf[srcp[x]]++; // safe
760 }
761 2 srcp += pitch;
762 }
763 }
764 else if (pixelsize == 2) {
765 for (int y = 0; y < h; y++) {
766 for (int x = 0; x < w; x++) {
767 accum_buf[min((int)(reinterpret_cast<const uint16_t *>(srcp)[x]), max_pixel_value)]++;
768 }
769 srcp += pitch;
770 }
771 }
772 else { //pixelsize==4 float
773 // for float results are always checked with 16 bit precision only
774 // or else we cannot populate non-digital steps with this standard method
775 // See similar in colors, ColorYUV analyze
776 const bool chroma = (plane == PLANAR_U) || (plane == PLANAR_V);
777 if (chroma) {
778 const float shift = 32768.0f;
779 for (int y = 0; y < h; y++) {
780 for (int x = 0; x < w; x++) {
781 // -0.5..0.5 to 0..65535
782 const float pixel = reinterpret_cast<const float *>(srcp)[x];
783 accum_buf[clamp((int)(65535.0f*pixel + shift + 0.5f), 0, 65535)]++;
784 }
785 srcp += pitch;
786 }
787 }
788 else {
789 for (int y = 0; y < h; y++) {
790 for (int x = 0; x < w; x++) {
791 const float pixel = reinterpret_cast<const float *>(srcp)[x];
792 accum_buf[clamp((int)(65535.0f * pixel + 0.5f), 0, 65535)]++;
793 }
794 srcp += pitch;
795 }
796 }
797 }
798
799 1 int pixels = w*h;
800 1 threshold /=100.0; // Thresh now 0-1
801 1 threshold = clamp(threshold, 0.0, 1.0);
802
803 1 unsigned int tpixels = (unsigned int)(pixels*threshold);
804
805 int retval;
806
807 // Find the value we need.
808
1/2
✗ Branch 202 → 203 not taken.
✓ Branch 202 → 209 taken 1 time.
1 if (mode == MinMaxPlane::MIN) {
809 // threshold == 0 was covered already
810 unsigned int counted=0;
811 retval = buffersize - 1;
812 for (int i = 0; i< buffersize;i++) {
813 counted += accum_buf[i];
814 if (counted>tpixels) {
815 retval = i;
816 break;
817 }
818 }
819 }
820
1/2
✓ Branch 209 → 210 taken 1 time.
✗ Branch 209 → 216 not taken.
1 else if (mode == MinMaxPlane::MAX) {
821 1 unsigned int counted=0;
822 1 retval = 0;
823
1/2
✓ Branch 214 → 211 taken 184 times.
✗ Branch 214 → 215 not taken.
184 for (int i = buffersize-1; i>=0;i--) {
824 184 counted += accum_buf[i];
825
2/2
✓ Branch 211 → 212 taken 1 time.
✓ Branch 211 → 213 taken 183 times.
184 if (counted>tpixels) {
826 1 retval = i;
827 1 break;
828 }
829 }
830 }
831 else if (mode == MinMaxPlane::STATS && threshold == 0) {
832 stats_thresholded_min = (float)stats_min;
833 stats_thresholded_max = (float)stats_max;
834 retval = -1; // stats: n/a
835 }
836 else if (mode == MinMaxPlane::MINMAX_DIFFERENCE || mode == MinMaxPlane::STATS) {
837 // thresholded case
838 unsigned int counted=0;
839 int i, t_min = 0;
840 // Find min
841 for (i = 0; i < buffersize;i++) {
842 counted += accum_buf[i];
843 if (counted>tpixels) {
844 t_min=i;
845 break;
846 }
847 }
848
849 // Find max
850 counted=0;
851 int t_max = buffersize-1;
852 for (i = buffersize-1; i>=0;i--) {
853 counted += accum_buf[i];
854 if (counted>tpixels) {
855 t_max=i;
856 break;
857 }
858 }
859
860 retval = t_max - t_min; // results <0 will be returned if threshold > 50
861 stats_thresholded_min = (float)t_min;
862 stats_thresholded_max = (float)t_max;
863 }
864
865
1/2
✗ Branch 232 → 233 not taken.
✓ Branch 232 → 239 taken 1 time.
1 if (mode == MinMaxPlane::STATS) {
866 // for STATS we already have min and max, thresholded min and max
867 // let's gather median, which is equal to 50% MIN
868 // comment: no separate MEDIAN mode is used, already converted to MIN 50% in ctor
869 unsigned int tpixels = (unsigned int)(pixels * 0.5f);
870 unsigned int counted = 0;
871 retval = buffersize - 1;
872 for (int i = 0; i < buffersize; i++) {
873 counted += accum_buf[i];
874 if (counted > tpixels) {
875 retval = i;
876 break;
877 }
878 }
879 stats_median = (float)retval;
880 }
881
882
1/2
✓ Branch 239 → 240 taken 1 time.
✗ Branch 239 → 241 not taken.
1 delete[] accum_buf;
883 //_RPT2(0, "End of MinMax cn=%d n=%d\r", cn.AsInt(), n);
884
885
1/2
✗ Branch 241 → 242 not taken.
✓ Branch 241 → 288 taken 1 time.
1 if (mode == MinMaxPlane::STATS) {
886 if (pixelsize == 4) {
887 const bool chroma = (plane == PLANAR_U) || (plane == PLANAR_V);
888 const float shift = chroma ? 32768.0f : 0;
889 stats_thresholded_min = (float)((double)(stats_thresholded_min - shift) / (buffersize - 1)); // convert back to float, /65535
890 stats_thresholded_max = (float)((double)(stats_thresholded_max - shift) / (buffersize - 1)); // convert back to float, /65535
891 stats_median = (float)((double)(stats_median - shift) / (buffersize - 1)); // convert back to float, /65535
892 }
893
894 AVSValue result[] = { stats_min, stats_max, stats_thresholded_min, stats_thresholded_max, stats_median, stats_average };
895 AVSValue ret = AVSValue(result, 6);
896 if (setvar) {
897 env->SetGlobalVar("PlaneStats_min", stats_min);
898 env->SetGlobalVar("PlaneStats_max", stats_max);
899 env->SetGlobalVar("PlaneStats_thmin", stats_thresholded_min);
900 env->SetGlobalVar("PlaneStats_thmax", stats_thresholded_max);
901 env->SetGlobalVar("PlaneStats_median", stats_median);
902 env->SetGlobalVar("PlaneStats_average", stats_average);
903 }
904
905 return ret;
906 }
907
908
1/2
✗ Branch 288 → 289 not taken.
✓ Branch 288 → 300 taken 1 time.
1 if (pixelsize == 4) {
909 const bool chroma = (plane == PLANAR_U) || (plane == PLANAR_V);
910 if (chroma && (mode == MIN || mode == MAX)) {
911 const float shift = 32768.0f;
912 return AVSValue((double)(retval - shift) / (buffersize - 1)); // convert back to float, /65535
913 }
914 else {
915 return AVSValue((double)retval / (buffersize - 1)); // convert back to float, /65535
916 }
917 }
918 else
919
1/2
✓ Branch 300 → 301 taken 1 time.
✗ Branch 300 → 398 not taken.
1 return AVSValue(retval);
920 1 }
921
922
923 AVSValue GetProperty::Create(AVSValue args, void* user_data, IScriptEnvironment* env_) {
924 InternalEnvironment* IEnv = GetAndRevealCamouflagedEnv(env_);
925 IScriptEnvironment* env = static_cast<IScriptEnvironment*>(IEnv);
926
927 AVSValue clip = args[0];
928 if (!clip.IsClip())
929 env->ThrowError("propGetxxxxx: No clip supplied!");
930
931 PClip child = clip.AsClip();
932 VideoInfo vi = child->GetVideoInfo();
933
934 AVSValue cn = env->GetVarDef("current_frame");
935 const bool calledFromRunTime = cn.IsInt();
936
937 int propType = (int)(intptr_t)user_data;
938 // vUnset, vInt, vFloat, vData, vNode/Clip, vFrame/*, vMethod*/ }
939 // 0: auto
940 // 1: integer (int64 long)
941 // 2: float (double)
942 // 3: char (null terminated data)
943 // 4: Clip
944
945 const char* propName = args[1].AsString();
946 const int index = args[2].AsInt(0);
947 const int offset = args[3].AsInt(0);
948
949 int n = calledFromRunTime ? cn.AsInt() : 0;
950 n = min(max(n + offset, 0), vi.num_frames - 1);
951
952 PVideoFrame src = child->GetFrame(n, env);
953
954 const AVSMap* avsmap = env->getFramePropsRO(src);
955
956 int error = 0;
957
958 // check auto
959 if (propType == 0) {
960 char res = env->propGetType(avsmap, propName);
961 // 'u'nset, 'i'nteger, 'f'loat, 's'string, 'c'lip, 'v'ideoframe, 'm'ethod };
962 switch (res) {
963 case 'u': return AVSValue(); // unSet = AVS undefined
964 case 'v': env->ThrowError("Error getting frame property \"%s\": video frames not supported as function return values", propName);
965 break;
966 case 'i': propType = 1; break;
967 case 'f': propType = 2; break;
968 case 's': propType = 3; break;
969 case 'c': propType = 4; break;
970 default:
971 env->ThrowError("Error getting frame property \"%s\": type '%c' not supported", propName, res);
972 }
973 }
974
975 if (propType == 1) {
976 int64_t result = env->propGetInt(avsmap, propName, index, &error);
977 if(!error)
978 return AVSValue(result); // v11: no need for (int) cast
979 }
980 else if (propType == 2) {
981 double result = env->propGetFloat(avsmap, propName, index, &error);
982 if (!error)
983 return AVSValue(result);
984 }
985 else if (propType == 3) {
986 const char *result = env->propGetData(avsmap, propName, index, &error);
987 if (!error) {
988 result = env->SaveString(result); // property had its own storage
989 return AVSValue(result);
990 }
991 }
992 else if (propType == 4) {
993 PClip result = env->propGetClip(avsmap, propName, index, &error);
994 if (!error)
995 return AVSValue(result);
996 }
997 else {
998 error = AVSGetPropErrors::GETPROPERROR_TYPE;
999 }
1000
1001 const char* error_msg = nullptr;
1002
1003 // really, errors are bits
1004 if (error & AVSGetPropErrors::GETPROPERROR_UNSET)
1005 error_msg = "property is not set";
1006 else if (error & AVSGetPropErrors::GETPROPERROR_TYPE)
1007 error_msg = "wrong type";
1008 else if (error & AVSGetPropErrors::GETPROPERROR_INDEX)
1009 error_msg = "index error"; // arrays
1010
1011 if (error)
1012 env->ThrowError("Error getting frame property \"%s\": %s ", propName, error_msg);
1013
1014 return AVSValue();
1015 }
1016
1017 AVSValue GetPropertyAsArray::Create(AVSValue args, void* , IScriptEnvironment* env_)
1018 {
1019 InternalEnvironment* IEnv = GetAndRevealCamouflagedEnv(env_);
1020 IScriptEnvironment* env = static_cast<IScriptEnvironment*>(IEnv);
1021
1022 AVSValue clip = args[0];
1023 if (!clip.IsClip())
1024 env->ThrowError("propGetAsArray: No clip supplied!");
1025
1026 PClip child = clip.AsClip();
1027 VideoInfo vi = child->GetVideoInfo();
1028
1029 AVSValue cn = env->GetVarDef("current_frame");
1030 const bool calledFromRunTime = cn.IsInt();
1031
1032 const char* propName = args[1].AsString();
1033 const int offset = args[2].AsInt(0);
1034
1035 int n = calledFromRunTime ? cn.AsInt() : 0;
1036 n = min(max(n + offset, 0), vi.num_frames - 1);
1037
1038 PVideoFrame src = child->GetFrame(n, env);
1039
1040 const AVSMap* avsmap = env->getFramePropsRO(src);
1041
1042 int error = 0;
1043
1044 char propType = env->propGetType(avsmap, propName);
1045 if (propType == 'u') {
1046 // special: zero array
1047 return AVSValue(nullptr, 0);
1048 }
1049 // check auto
1050 int size = env->propNumElements(avsmap, propName);
1051
1052 std::vector<AVSValue> result(size);
1053
1054 // propGetIntArray or propGetFloatArray is available
1055 // Pre interface V11: AVSValue is int and float, prop arrays are int64_t and double
1056 if (propType == 'i') {
1057 const int64_t* arr = env->propGetIntArray(avsmap, propName, &error);
1058 for (int i = 0; i < size; ++i)
1059 result[i] = arr[i]; // v11: no need for (int) cast
1060 }
1061 else if (propType == 'f') {
1062 const double* arr = env->propGetFloatArray(avsmap, propName, &error);
1063 for (int i = 0; i < size; ++i)
1064 result[i] = arr[i]; // v11: no need for (float) cast
1065 }
1066 else
1067 {
1068 // generic
1069 for (int i = 0; i < size; ++i) {
1070 AVSValue elem;
1071 switch (propType) {
1072 case 'i': elem = AVSValue(env->propGetInt(avsmap, propName, i, &error)); break; // though handled earlier
1073 case 'f': elem = AVSValue(env->propGetFloat(avsmap, propName, i, &error)); break; // though handled earlier
1074 case 's': {
1075 const char* s = env->propGetData(avsmap, propName, i, &error);
1076 if (!error)
1077 elem = AVSValue(env->SaveString(s));
1078 }
1079 break;
1080 case 'v': elem = AVSValue(env->propGetFrame(avsmap, propName, i, &error)); break;
1081 case 'c': elem = AVSValue(env->propGetClip(avsmap, propName, i, &error)); break;
1082 default:
1083 elem = AVSValue();
1084 }
1085 if (error)
1086 break;
1087 result[i] = elem;
1088 }
1089 }
1090
1091 const char* error_msg = nullptr;
1092
1093 // really, errors are bits
1094 if (error & AVSGetPropErrors::GETPROPERROR_UNSET)
1095 error_msg = "property is not set";
1096 else if (error & AVSGetPropErrors::GETPROPERROR_TYPE)
1097 error_msg = "wrong type";
1098 else if (error & AVSGetPropErrors::GETPROPERROR_INDEX)
1099 error_msg = "index error"; // arrays
1100
1101 if (error)
1102 env->ThrowError("propGetAsArray: Error getting frame property \"%s\": %s ", propName, error_msg);
1103
1104 return AVSValue(result.data(), size); // array deep copy
1105 }
1106
1107 // propGetAll
1108 // fills an AVSValue array with key-value pairs
1109 // array size will be numProps
1110 // each array element is a two dimensional array [key, value]
1111 // value can be an array as well, depending on the property
1112 // only int, float and string data extracted
1113 1 AVSValue GetAllProperties::Create(AVSValue args, void*, IScriptEnvironment* env_)
1114 {
1115
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 239 not taken.
1 InternalEnvironment* IEnv = GetAndRevealCamouflagedEnv(env_);
1116 1 IScriptEnvironment* env = static_cast<IScriptEnvironment*>(IEnv);
1117
1118
2/4
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 239 not taken.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 239 not taken.
1 AVSValue clip = args[0];
1119
2/4
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 237 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 1 time.
1 if (!clip.IsClip())
1120 env->ThrowError("propGetAll: No clip supplied!");
1121
1122
1/2
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 237 not taken.
1 PClip child = clip.AsClip();
1123
1/2
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 235 not taken.
1 VideoInfo vi = child->GetVideoInfo();
1124
1125
2/4
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 157 not taken.
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 155 not taken.
1 AVSValue cn = env->GetVarDef("current_frame");
1126
1/2
✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 233 not taken.
1 const bool calledFromRunTime = cn.IsInt();
1127
1128
2/4
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 233 not taken.
✓ Branch 16 → 17 taken 1 time.
✗ Branch 16 → 233 not taken.
1 const int offset = args[1].AsInt(0);
1129
1130
1/4
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 20 taken 1 time.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 233 not taken.
1 int n = calledFromRunTime ? cn.AsInt() : 0;
1131 1 n = min(max(n + offset, 0), vi.num_frames - 1);
1132
1133
1/2
✓ Branch 24 → 25 taken 1 time.
✗ Branch 24 → 233 not taken.
1 PVideoFrame src = child->GetFrame(n, env);
1134
1135
1/2
✓ Branch 25 → 26 taken 1 time.
✗ Branch 25 → 231 not taken.
1 const AVSMap* avsmap = env->getFramePropsRO(src);
1136
1137
1/2
✓ Branch 26 → 27 taken 1 time.
✗ Branch 26 → 231 not taken.
1 const int propNum = env->propNumKeys(avsmap);
1138
1139
1/2
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 30 taken 1 time.
1 if (0 == propNum)
1140 return AVSValue(nullptr, 0); // zero sized array
1141
1142
1/2
✓ Branch 32 → 33 taken 1 time.
✗ Branch 32 → 158 not taken.
1 std::vector<AVSValue> result(propNum);
1143
1144
2/2
✓ Branch 144 → 35 taken 1 time.
✓ Branch 144 → 145 taken 1 time.
2 for (int index = 0; index < propNum; index++) {
1145
1/2
✓ Branch 37 → 38 taken 1 time.
✗ Branch 37 → 161 not taken.
1 std::vector<AVSValue> pair(2);
1146
1/2
✓ Branch 39 → 40 taken 1 time.
✗ Branch 39 → 226 not taken.
1 const char* propName = env->propGetKey(avsmap, index);
1147
3/6
✓ Branch 40 → 41 taken 1 time.
✗ Branch 40 → 166 not taken.
✓ Branch 41 → 42 taken 1 time.
✗ Branch 41 → 166 not taken.
✓ Branch 43 → 44 taken 1 time.
✗ Branch 43 → 164 not taken.
1 pair[0] = env->SaveString(propName);
1148
1/2
✓ Branch 45 → 46 taken 1 time.
✗ Branch 45 → 226 not taken.
1 const char propType = env->propGetType(avsmap, propName);
1149
1/2
✓ Branch 46 → 47 taken 1 time.
✗ Branch 46 → 226 not taken.
1 const int propNumElements = env->propNumElements(avsmap, propName);
1150
1151 int error;
1152
1153
1/2
✓ Branch 47 → 48 taken 1 time.
✗ Branch 47 → 226 not taken.
1 AVSValue elem;
1154
1/2
✓ Branch 48 → 49 taken 1 time.
✗ Branch 48 → 134 not taken.
1 if (propType == 'u') {
1155 // unSet: undefined value
1156 }
1157
1/2
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 74 taken 1 time.
1 else if (propType == 'i') {
1158 if(propNumElements == 1)
1159 elem = AVSValue(env->propGetInt(avsmap, propName, 0, &error)); // v11: no need for (int) cast
1160 else {
1161 std::vector<AVSValue> avsarr(propNumElements);
1162 const int64_t* arr = env->propGetIntArray(avsmap, propName, &error);
1163 for (int i = 0; i < propNumElements; ++i)
1164 avsarr[i] = arr[i]; // v11: no need for (int) cast
1165 elem = AVSValue(avsarr.data(), propNumElements); // array deep copy
1166 }
1167 }
1168
1/2
✗ Branch 74 → 75 not taken.
✓ Branch 74 → 99 taken 1 time.
1 else if (propType == 'f') {
1169 if(propNumElements == 1)
1170 elem = AVSValue(env->propGetFloat(avsmap, propName, 0, &error)); // since v11 no need for (float) cast
1171 else {
1172 std::vector<AVSValue> avsarr(propNumElements);
1173 const double* arr = env->propGetFloatArray(avsmap, propName, &error);
1174 for (int i = 0; i < propNumElements; ++i)
1175 avsarr[i] = arr[i]; // v11: no need for (float) cast
1176 elem = AVSValue(avsarr.data(), propNumElements); // array deep copy
1177 }
1178 }
1179
1/2
✓ Branch 99 → 100 taken 1 time.
✗ Branch 99 → 107 not taken.
1 else if (propType == 's') {
1180 // no string arrays
1181
1/2
✓ Branch 100 → 101 taken 1 time.
✗ Branch 100 → 224 not taken.
1 const char* s = env->propGetData(avsmap, propName, 0, &error);
1182
1/2
✓ Branch 101 → 102 taken 1 time.
✗ Branch 101 → 134 not taken.
1 if (!error)
1183
3/6
✓ Branch 102 → 103 taken 1 time.
✗ Branch 102 → 199 not taken.
✓ Branch 103 → 104 taken 1 time.
✗ Branch 103 → 199 not taken.
✓ Branch 104 → 105 taken 1 time.
✗ Branch 104 → 197 not taken.
1 elem = AVSValue(env->SaveString(s));
1184 }
1185 else if (propType == 'c') {
1186 if (propNumElements == 1)
1187 elem = AVSValue(env->propGetClip(avsmap, propName, 0, &error));
1188 else {
1189 std::vector<AVSValue> avsarr(propNumElements);
1190 for (int i = 0; i < propNumElements; ++i)
1191 avsarr[i] = AVSValue(env->propGetClip(avsmap, propName, i, &error));
1192 elem = AVSValue(avsarr.data(), propNumElements); // array deep copy
1193 }
1194 }
1195 else {
1196 // 'v': ignore no such AVSValue in Avisynth
1197 }
1198
1199
1/2
✓ Branch 135 → 136 taken 1 time.
✗ Branch 135 → 224 not taken.
1 pair[1] = elem;
1200
2/4
✓ Branch 137 → 138 taken 1 time.
✗ Branch 137 → 223 not taken.
✓ Branch 139 → 140 taken 1 time.
✗ Branch 139 → 221 not taken.
1 result[index] = AVSValue(pair.data(), 2); // arrays in arrays, automatic deep copy
1201 1 }
1202
1203
1/2
✓ Branch 146 → 147 taken 1 time.
✗ Branch 146 → 229 not taken.
1 return AVSValue(result.data(), propNum); // array deep copy
1204 1 }
1205
1206 // e.g. string length
1207 AVSValue GetPropertyDataSize::Create(AVSValue args, void* , IScriptEnvironment* env_) {
1208 InternalEnvironment* IEnv = GetAndRevealCamouflagedEnv(env_);
1209 IScriptEnvironment* env = static_cast<IScriptEnvironment*>(IEnv);
1210
1211 AVSValue clip = args[0];
1212 if (!clip.IsClip())
1213 env->ThrowError("propGetDataSize: No clip supplied!");
1214
1215 PClip child = clip.AsClip();
1216 VideoInfo vi = child->GetVideoInfo();
1217
1218 AVSValue cn = env->GetVarDef("current_frame");
1219 const bool calledFromRunTime = cn.IsInt();
1220
1221 const char* propName = args[1].AsString();
1222 const int index = args[2].AsInt(0);
1223 const int offset = args[3].AsInt(0);
1224
1225 int n = calledFromRunTime ? cn.AsInt() : 0;
1226 n = min(max(n + offset, 0), vi.num_frames - 1);
1227
1228 PVideoFrame src = child->GetFrame(n, env);
1229
1230 const AVSMap* avsmap = env->getFramePropsRO(src);
1231
1232 int error = 0;
1233
1234 int size = env->propGetDataSize(avsmap, propName, index, &error);
1235 if (!error)
1236 return AVSValue(size);
1237
1238 const char* error_msg = nullptr;
1239
1240 // really, errors are bits
1241 if (error & AVSGetPropErrors::GETPROPERROR_UNSET)
1242 error_msg = "property is not set";
1243 else if (error & AVSGetPropErrors::GETPROPERROR_TYPE)
1244 error_msg = "wrong type";
1245 else if (error & AVSGetPropErrors::GETPROPERROR_INDEX)
1246 error_msg = "index error"; // arrays
1247
1248 if (error)
1249 env->ThrowError("Error getting frame property data size \"%s\": %s ", propName, error_msg);
1250
1251 return AVSValue();
1252 }
1253
1254 // array size of a given property, (by setProp append mode arrays can be constructed)
1255 AVSValue GetPropertyNumElements::Create(AVSValue args, void*, IScriptEnvironment* env_) {
1256 InternalEnvironment* IEnv = GetAndRevealCamouflagedEnv(env_);
1257 IScriptEnvironment* env = static_cast<IScriptEnvironment*>(IEnv);
1258
1259 AVSValue clip = args[0];
1260 if (!clip.IsClip())
1261 env->ThrowError("propNumElements: No clip supplied!");
1262
1263 PClip child = clip.AsClip();
1264 VideoInfo vi = child->GetVideoInfo();
1265
1266 AVSValue cn = env->GetVarDef("current_frame");
1267 const bool calledFromRunTime = cn.IsInt();
1268
1269 const char* propName = args[1].AsString();
1270 const int offset = args[2].AsInt(0);
1271
1272 int n = calledFromRunTime ? cn.AsInt() : 0;
1273 n = min(max(n + offset, 0), vi.num_frames - 1);
1274
1275 PVideoFrame src = child->GetFrame(n, env);
1276
1277 const AVSMap* avsmap = env->getFramePropsRO(src);
1278
1279 try {
1280 int size = env->propNumElements(avsmap, propName);
1281 return AVSValue(size);
1282 }
1283 catch (const AvisynthError& error) {
1284 env->ThrowError("propNumElements: %s", error.msg);
1285 }
1286
1287 return AVSValue();
1288 }
1289
1290 // returns integer enums instead of char (string)
1291 AVSValue GetPropertyType::Create(AVSValue args, void*, IScriptEnvironment* env_) {
1292 InternalEnvironment* IEnv = GetAndRevealCamouflagedEnv(env_);
1293 IScriptEnvironment* env = static_cast<IScriptEnvironment*>(IEnv);
1294
1295 AVSValue clip = args[0];
1296 if (!clip.IsClip())
1297 env->ThrowError("propGetType: No clip supplied!");
1298
1299 PClip child = clip.AsClip();
1300 VideoInfo vi = child->GetVideoInfo();
1301
1302 AVSValue cn = env->GetVarDef("current_frame");
1303 const bool calledFromRunTime = cn.IsInt();
1304
1305 const char* propName = args[1].AsString();
1306 const int offset = args[2].AsInt(0);
1307
1308 int n = calledFromRunTime ? cn.AsInt() : 0;
1309 n = min(max(n + offset, 0), vi.num_frames - 1);
1310
1311 PVideoFrame src = child->GetFrame(n, env);
1312
1313 const AVSMap* avsmap = env->getFramePropsRO(src);
1314
1315 try {
1316 char prop_type = env->propGetType(avsmap, propName);
1317 // 'u'nset, 'i'nteger, 'f'loat, 's'string, 'c'lip, 'v'ideoframe, 'm'ethod };
1318 switch (prop_type) {
1319 case 'u': return 0;
1320 case 'i': return 1;
1321 case 'f': return 2;
1322 case 's': return 3;
1323 case 'c': return 4;
1324 case 'v': return 5;
1325 //case 'm': return 6;
1326 default:
1327 return -1;
1328 }
1329 }
1330 catch (const AvisynthError& error) {
1331 env->ThrowError("propGetType: %s", error.msg);
1332 }
1333
1334 return AVSValue();
1335 }
1336
1337
1338 // Number of properties (keys) for a frame
1339 AVSValue GetPropertyNumKeys::Create(AVSValue args, void*, IScriptEnvironment* env_) {
1340 InternalEnvironment* IEnv = GetAndRevealCamouflagedEnv(env_);
1341 IScriptEnvironment* env = static_cast<IScriptEnvironment*>(IEnv);
1342
1343 AVSValue clip = args[0];
1344 if (!clip.IsClip())
1345 env->ThrowError("propNumKeys: No clip supplied!");
1346
1347 PClip child = clip.AsClip();
1348 VideoInfo vi = child->GetVideoInfo();
1349
1350 AVSValue cn = env->GetVarDef("current_frame");
1351 const bool calledFromRunTime = cn.IsInt();
1352
1353 int n = calledFromRunTime ? cn.AsInt() : 0;
1354 int offset = args[1].AsInt(0);
1355 n = min(max(n + offset, 0), vi.num_frames - 1);
1356
1357 PVideoFrame src = child->GetFrame(n, env);
1358
1359 const AVSMap* avsmap = env->getFramePropsRO(src);
1360
1361 try {
1362 int size = env->propNumKeys(avsmap);
1363 return AVSValue(size);
1364 }
1365 catch (const AvisynthError& error) {
1366 env->ThrowError("propNumKeys: %s", error.msg);
1367 }
1368
1369 return AVSValue();
1370 }
1371
1372 // Get the name (key) of the Nth frame property
1373 AVSValue GetPropertyKeyByIndex::Create(AVSValue args, void*, IScriptEnvironment* env_) {
1374 InternalEnvironment* IEnv = GetAndRevealCamouflagedEnv(env_);
1375 IScriptEnvironment* env = static_cast<IScriptEnvironment*>(IEnv);
1376
1377 AVSValue clip = args[0];
1378 if (!clip.IsClip())
1379 env->ThrowError("propNumKeys: No clip supplied!");
1380
1381 PClip child = clip.AsClip();
1382 VideoInfo vi = child->GetVideoInfo();
1383
1384 AVSValue cn = env->GetVarDef("current_frame");
1385 const bool calledFromRunTime = cn.IsInt();
1386
1387 const int index = args[1].AsInt(0);
1388 const int offset = args[2].AsInt(0);
1389
1390 int n = calledFromRunTime ? cn.AsInt() : 0;
1391 n = min(max(n + offset, 0), vi.num_frames - 1);
1392
1393 PVideoFrame src = child->GetFrame(n, env);
1394
1395 const AVSMap* avsmap = env->getFramePropsRO(src);
1396
1397 try {
1398 const char* prop_name = env->propGetKey(avsmap, index);
1399 return AVSValue(env->SaveString(prop_name));
1400 }
1401 catch (const AvisynthError& error) {
1402 env->ThrowError("propGetKeyByIndex: %s", error.msg);
1403 }
1404
1405 return AVSValue();
1406 }
1407