GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 43.4% 272 / 0 / 627
Functions: 30.4% 7 / 0 / 23
Branches: 25.2% 439 / 0 / 1745

filters/planeswap.cpp
Line Branch Exec Source
1 // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al.
2 // http://avisynth.nl
3
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
17 // http://www.gnu.org/copyleft/gpl.html .
18 //
19 // Linking Avisynth statically or dynamically with other modules is making a
20 // combined work based on Avisynth. Thus, the terms and conditions of the GNU
21 // General Public License cover the whole combination.
22 //
23 // As a special exception, the copyright holders of Avisynth give you
24 // permission to link Avisynth with independent modules that communicate with
25 // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
26 // terms of these independent modules, and to copy and distribute the
27 // resulting combined work under terms of your choice, provided that
28 // every copy of the combined work is accompanied by a complete copy of
29 // the source code of Avisynth (the version of Avisynth used to produce the
30 // combined work), being distributed under the terms of the GNU General
31 // Public License plus this exception. An independent module is a module
32 // which is not derived from or based on Avisynth, such as 3rd-party filters,
33 // import and export plugins, or graphical user interfaces.
34
35
36 // Avisynth filter: Swap planes
37 // by Klaus Post
38 // adapted by Richard Berg (avisynth-dev@richardberg.net)
39 // iSSE code by Ian Brabham
40
41 #include <avs/config.h>
42 #ifdef AVS_WINDOWS
43 #include <avs/win.h>
44 #else
45 #include <avs/posix.h>
46 #endif
47 #include "planeswap.h"
48 #ifdef INTEL_INTRINSICS
49 #include "intel/planeswap_sse.h"
50 #include "intel/planeswap_avx2.h"
51 #endif
52 #include "../core/internal.h"
53 #include <algorithm>
54 #include <avs/alignment.h>
55 #include "../convert/convert_planar.h"
56 #include "../convert/convert_rgb.h"
57 #include "../convert/convert.h"
58 #include "../convert/convert_helper.h"
59 #include "stdint.h"
60
61
62 /********************************************************************
63 ***** Declare index of new filters for Avisynth's filter engine *****
64 ********************************************************************/
65
66 extern const AVSFunction Swap_filters[] = {
67 { "SwapUV", BUILTIN_FUNC_PREFIX, "c", SwapUV::CreateSwapUV },
68 { "UToY", BUILTIN_FUNC_PREFIX, "c", SwapUVToY::CreateUToY },
69 { "VToY", BUILTIN_FUNC_PREFIX, "c", SwapUVToY::CreateVToY },
70 { "UToY8", BUILTIN_FUNC_PREFIX, "c", SwapUVToY::CreateUToY8 },
71 { "VToY8", BUILTIN_FUNC_PREFIX, "c", SwapUVToY::CreateVToY8 },
72 { "ExtractY", BUILTIN_FUNC_PREFIX, "c", SwapUVToY::CreateYToY8 }, // differs, YUY2 checks inside
73 { "ExtractU", BUILTIN_FUNC_PREFIX, "c", SwapUVToY::CreateUToY8 }, // differs, YUY2 checks inside
74 { "ExtractV", BUILTIN_FUNC_PREFIX, "c", SwapUVToY::CreateVToY8 }, // differs, YUY2 checks inside
75 { "ExtractA", BUILTIN_FUNC_PREFIX, "c", SwapUVToY::CreateAnyToY8, (void *)SwapUVToY::AToY8 },
76 { "ExtractR", BUILTIN_FUNC_PREFIX, "c", SwapUVToY::CreateAnyToY8, (void *)SwapUVToY::RToY8 },
77 { "ExtractG", BUILTIN_FUNC_PREFIX, "c", SwapUVToY::CreateAnyToY8, (void *)SwapUVToY::GToY8 },
78 { "ExtractB", BUILTIN_FUNC_PREFIX, "c", SwapUVToY::CreateAnyToY8, (void *)SwapUVToY::BToY8 },
79 { "YToUV", BUILTIN_FUNC_PREFIX, "cc", SwapYToUV::CreateYToUV },
80 { "YToUV", BUILTIN_FUNC_PREFIX, "ccc", SwapYToUV::CreateYToYUV },
81 { "YToUV", BUILTIN_FUNC_PREFIX, "cccc", SwapYToUV::CreateYToYUVA }, // avs+ alpha planes
82 { "PlaneToY", BUILTIN_FUNC_PREFIX, "c[plane]s", SwapUVToY::CreatePlaneToY8 },
83 { "CombinePlanes", BUILTIN_FUNC_PREFIX, "c[planes]s[source_planes]s[pixel_type]s[sample_clip]c", CombinePlanes::CreateCombinePlanes, (void *)1},
84 { "CombinePlanes", BUILTIN_FUNC_PREFIX, "cc[planes]s[source_planes]s[pixel_type]s[sample_clip]c", CombinePlanes::CreateCombinePlanes, (void *)2},
85 { "CombinePlanes", BUILTIN_FUNC_PREFIX, "ccc[planes]s[source_planes]s[pixel_type]s[sample_clip]c", CombinePlanes::CreateCombinePlanes, (void *)3},
86 { "CombinePlanes", BUILTIN_FUNC_PREFIX, "cccc[planes]s[source_planes]s[pixel_type]s[sample_clip]c", CombinePlanes::CreateCombinePlanes, (void *)4},
87 { 0 }
88 };
89
90
91 /**************************************
92 * Swap - swaps UV on planar maps
93 **************************************/
94
95 static void yuy2_swap_c(const BYTE* srcp, BYTE* dstp, int src_pitch, int dst_pitch, int width, int height)
96 {
97 for (int y = 0; y < height; ++y) {
98 for (int x = 0; x < width; x += 4) {
99 dstp[x + 0] = srcp[x + 0];
100 dstp[x + 3] = srcp[x + 1];
101 dstp[x + 2] = srcp[x + 2];
102 dstp[x + 1] = srcp[x + 3];
103 }
104 srcp += src_pitch;
105 dstp += dst_pitch;
106 }
107 }
108
109 AVSValue __cdecl SwapUV::CreateSwapUV(AVSValue args, void* , IScriptEnvironment* env)
110 {
111 PClip p = args[0].AsClip();
112 if (p->GetVideoInfo().NumComponents() == 1)
113 return p;
114 return new SwapUV(p, env);
115 }
116
117
118
2/4
✓ Branch 2 → 3 taken 6 times.
✗ Branch 2 → 16 not taken.
✓ Branch 3 → 4 taken 6 times.
✗ Branch 3 → 14 not taken.
6 SwapUV::SwapUV(PClip _child, IScriptEnvironment* env) : GenericVideoFilter(_child)
119 {
120
6/10
✓ Branch 5 → 6 taken 6 times.
✗ Branch 5 → 17 not taken.
✓ Branch 6 → 7 taken 3 times.
✓ Branch 6 → 10 taken 3 times.
✓ Branch 7 → 8 taken 3 times.
✗ Branch 7 → 17 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 3 times.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 6 times.
6 if (!vi.IsYUV() && !vi.IsYUVA())
121 env->ThrowError("SwapUV: YUV or YUVA data only!");
122 6 }
123
124 6 PVideoFrame __stdcall SwapUV::GetFrame(int n, IScriptEnvironment* env)
125 {
126
1/2
✓ Branch 3 → 4 taken 6 times.
✗ Branch 3 → 72 not taken.
6 PVideoFrame src = child->GetFrame(n, env);
127
128
2/4
✓ Branch 4 → 5 taken 6 times.
✗ Branch 4 → 70 not taken.
✓ Branch 5 → 6 taken 6 times.
✗ Branch 5 → 38 not taken.
6 if (vi.IsPlanar()) {
129 // Abuse subframe to flip the UV plane pointers -- extremely fast but a bit naughty!
130 // !! if offsets would be size_t, be cautious when you subtract two unsigned size_t variables
131
2/4
✓ Branch 7 → 8 taken 6 times.
✗ Branch 7 → 70 not taken.
✓ Branch 9 → 10 taken 6 times.
✗ Branch 9 → 70 not taken.
6 const int uvoffset = src->GetOffset(PLANAR_V) - src->GetOffset(PLANAR_U); // very naughty - don't do this at home!!
132
3/4
✓ Branch 10 → 11 taken 6 times.
✗ Branch 10 → 70 not taken.
✓ Branch 11 → 12 taken 3 times.
✓ Branch 11 → 25 taken 3 times.
6 if (vi.NumComponents() == 4) {
133 3 return env->SubframePlanarA(src, 0, src->GetPitch(PLANAR_Y), src->GetRowSize(PLANAR_Y), src->GetHeight(PLANAR_Y),
134
6/12
✓ Branch 13 → 14 taken 3 times.
✗ Branch 13 → 70 not taken.
✓ Branch 15 → 16 taken 3 times.
✗ Branch 15 → 70 not taken.
✓ Branch 17 → 18 taken 3 times.
✗ Branch 17 → 70 not taken.
✓ Branch 19 → 20 taken 3 times.
✗ Branch 19 → 70 not taken.
✓ Branch 20 → 21 taken 3 times.
✗ Branch 20 → 64 not taken.
✓ Branch 21 → 22 taken 3 times.
✗ Branch 21 → 62 not taken.
3 uvoffset, -uvoffset, src->GetPitch(PLANAR_V), 0);
135 }
136 else {
137 3 return env->SubframePlanar(src, 0, src->GetPitch(PLANAR_Y), src->GetRowSize(PLANAR_Y), src->GetHeight(PLANAR_Y),
138
6/12
✓ Branch 26 → 27 taken 3 times.
✗ Branch 26 → 70 not taken.
✓ Branch 28 → 29 taken 3 times.
✗ Branch 28 → 70 not taken.
✓ Branch 30 → 31 taken 3 times.
✗ Branch 30 → 70 not taken.
✓ Branch 32 → 33 taken 3 times.
✗ Branch 32 → 70 not taken.
✓ Branch 33 → 34 taken 3 times.
✗ Branch 33 → 67 not taken.
✓ Branch 34 → 35 taken 3 times.
✗ Branch 34 → 65 not taken.
3 uvoffset, -uvoffset, src->GetPitch(PLANAR_V));
139 }
140 }
141
142 // YUY2
143 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
144 const BYTE* srcp = src->GetReadPtr();
145 BYTE* dstp = dst->GetWritePtr();
146 int src_pitch = src->GetPitch();
147 int dst_pitch = dst->GetPitch();
148 int rowsize = src->GetRowSize();
149 #ifdef INTEL_INTRINSICS
150 if ((env->GetCPUFlags() & CPUF_SSSE3))
151 yuy2_swap_ssse3(srcp, dstp, src_pitch, dst_pitch, rowsize, vi.height);
152 else if ((env->GetCPUFlags() & CPUF_SSE2))
153 yuy2_swap_sse2(srcp, dstp, src_pitch, dst_pitch, rowsize, vi.height);
154 #ifdef X86_32
155 else if (env->GetCPUFlags() & CPUF_INTEGER_SSE) // need pshufw
156 yuy2_swap_isse(srcp, dstp, src_pitch, dst_pitch, rowsize, vi.height);
157 #endif
158 else
159 #endif
160 {
161 yuy2_swap_c(srcp, dstp, src_pitch, dst_pitch, rowsize, vi.height);
162 }
163 return dst;
164 6 }
165
166
167 AVSValue __cdecl SwapUVToY::CreateUToY(AVSValue args, void* , IScriptEnvironment* env)
168 {
169 return new SwapUVToY(args[0].AsClip(), UToY, env);
170 }
171
172 AVSValue __cdecl SwapUVToY::CreateUToY8(AVSValue args, void* , IScriptEnvironment* env)
173 {
174 PClip clip = args[0].AsClip();
175 return new SwapUVToY(clip, (clip->GetVideoInfo().IsYUY2()) ? YUY2UToY8 : UToY8, env);
176 }
177
178 AVSValue __cdecl SwapUVToY::CreateYToY8(AVSValue args, void* , IScriptEnvironment* env)
179 {
180 PClip clip = args[0].AsClip();
181 if(clip->GetVideoInfo().IsYUY2())
182 return new ConvertYUY2ToYV16_or_Y(clip, true /*to_y*/, env);
183 else
184 return new SwapUVToY(clip, YToY8, env);
185 }
186
187 AVSValue __cdecl SwapUVToY::CreateVToY(AVSValue args, void* , IScriptEnvironment* env)
188 {
189 return new SwapUVToY(args[0].AsClip(), VToY, env);
190 }
191
192 AVSValue __cdecl SwapUVToY::CreateVToY8(AVSValue args, void* , IScriptEnvironment* env)
193 {
194 PClip clip = args[0].AsClip();
195 return new SwapUVToY(clip, (clip->GetVideoInfo().IsYUY2()) ? YUY2VToY8 : VToY8, env);
196 }
197
198 AVSValue __cdecl SwapUVToY::CreateAnyToY8(AVSValue args, void* user_data, IScriptEnvironment* env)
199 {
200 int mode = (int)(intptr_t)(user_data);
201 PClip clip = args[0].AsClip();
202
203 // Packed RGB (RGB24/32/48/64): pass directly to SwapUVToY; GetFrame handles
204 // channel extraction with correct bottom-up row order. No planar conversion needed.
205
206 if(clip->GetVideoInfo().IsYUY2() && mode == YToY8)
207 return new ConvertYUY2ToYV16_or_Y(clip, true /*to_y*/, env);
208
209 if (clip->GetVideoInfo().IsY() && mode == YToY8)
210 return clip;
211
212 return new SwapUVToY(clip, mode, env);
213 }
214
215 AVSValue __cdecl SwapUVToY::CreatePlaneToY8(AVSValue args, void* , IScriptEnvironment* env) {
216 PClip clip = args[0].AsClip();
217
218 const VideoInfo& vi_input = clip->GetVideoInfo();
219
220 const char* plane = args[1].AsString("");
221 int mode = 0;
222 // enum {UToY=1, VToY, UToY8, VToY8, YUY2UToY8, YUY2VToY8, AToY8, RToY8, GToY8, BToY8, YToY8};
223 if (!lstrcmpi(plane, "Y")) mode = YToY8;
224 else if (!lstrcmpi(plane, "U")) mode = vi_input.IsYUY2() ? YUY2UToY8 : UToY8;
225 else if (!lstrcmpi(plane, "V")) mode = vi_input.IsYUY2() ? YUY2VToY8 : VToY8;
226 else if (!lstrcmpi(plane, "A")) mode = AToY8;
227 else if (!lstrcmpi(plane, "R")) mode = RToY8;
228 else if (!lstrcmpi(plane, "G")) mode = GToY8;
229 else if (!lstrcmpi(plane, "B")) mode = BToY8;
230 else env->ThrowError("PlaneToY: Invalid plane!");
231
232 return CreateAnyToY8(args, (void* )(intptr_t)mode, env);
233 }
234
235
236 19 SwapUVToY::SwapUVToY(PClip _child, int _mode, IScriptEnvironment* env)
237
2/4
✓ Branch 2 → 3 taken 19 times.
✗ Branch 2 → 78 not taken.
✓ Branch 3 → 4 taken 19 times.
✗ Branch 3 → 76 not taken.
19 : GenericVideoFilter(_child), mode(_mode)
238 {
239
9/14
✓ Branch 5 → 6 taken 19 times.
✗ Branch 5 → 12 not taken.
✓ Branch 6 → 7 taken 14 times.
✓ Branch 6 → 12 taken 5 times.
✓ Branch 7 → 8 taken 9 times.
✓ Branch 7 → 12 taken 5 times.
✓ Branch 8 → 9 taken 9 times.
✗ Branch 8 → 12 not taken.
✓ Branch 9 → 10 taken 9 times.
✗ Branch 9 → 12 not taken.
✓ Branch 10 → 11 taken 9 times.
✗ Branch 10 → 12 not taken.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 9 times.
19 bool YUVmode = mode == YToY8 || mode == UToY8 || mode == VToY8 || mode == UToY || mode == VToY || mode == YUY2UToY8 || mode == YUY2VToY8;
240
6/6
✓ Branch 14 → 15 taken 16 times.
✓ Branch 14 → 17 taken 3 times.
✓ Branch 15 → 16 taken 13 times.
✓ Branch 15 → 17 taken 3 times.
✓ Branch 16 → 17 taken 3 times.
✓ Branch 16 → 18 taken 10 times.
19 bool RGBmode = mode == RToY8 || mode == GToY8 || mode == BToY8;
241 19 bool Alphamode = mode == AToY8;
242
243 // RGB32/64 are packed RGBA; RGB24/48 have no alpha channel.
244
10/20
✓ Branch 19 → 20 taken 19 times.
✗ Branch 19 → 79 not taken.
✓ Branch 20 → 21 taken 19 times.
✗ Branch 20 → 29 not taken.
✓ Branch 21 → 22 taken 19 times.
✗ Branch 21 → 79 not taken.
✓ Branch 22 → 23 taken 19 times.
✗ Branch 22 → 29 not taken.
✓ Branch 23 → 24 taken 19 times.
✗ Branch 23 → 79 not taken.
✓ Branch 24 → 25 taken 19 times.
✗ Branch 24 → 29 not taken.
✓ Branch 25 → 26 taken 19 times.
✗ Branch 25 → 79 not taken.
✓ Branch 26 → 27 taken 19 times.
✗ Branch 26 → 29 not taken.
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 19 times.
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 19 times.
19 if(!vi.IsYUVA() && !vi.IsPlanarRGBA() && !(vi.IsRGB32() || vi.IsRGB64()) && Alphamode)
245 env->ThrowError("PlaneToY: Clip has no Alpha channel!");
246
247
7/12
✓ Branch 32 → 33 taken 19 times.
✗ Branch 32 → 79 not taken.
✓ Branch 33 → 34 taken 9 times.
✓ Branch 33 → 38 taken 10 times.
✓ Branch 34 → 35 taken 9 times.
✗ Branch 34 → 79 not taken.
✓ Branch 35 → 36 taken 9 times.
✗ Branch 35 → 38 not taken.
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 38 taken 9 times.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 19 times.
19 if (!vi.IsYUV() && !vi.IsYUVA() && YUVmode )
248 env->ThrowError("PlaneToY: clip is not YUV!");
249
250 // IsRGB() covers both packed (RGB24/32/48/64) and planar RGB/RGBA.
251
5/8
✓ Branch 41 → 42 taken 19 times.
✗ Branch 41 → 79 not taken.
✓ Branch 42 → 43 taken 10 times.
✓ Branch 42 → 45 taken 9 times.
✗ Branch 43 → 44 not taken.
✓ Branch 43 → 45 taken 10 times.
✗ Branch 46 → 47 not taken.
✓ Branch 46 → 48 taken 19 times.
19 if (!vi.IsRGB() && RGBmode)
252 env->ThrowError("PlaneToY: clip is not RGB!");
253
254
3/8
✓ Branch 48 → 49 taken 19 times.
✗ Branch 48 → 79 not taken.
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 52 taken 19 times.
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 52 not taken.
✗ Branch 53 → 54 not taken.
✓ Branch 53 → 55 taken 19 times.
19 if (vi.NumComponents() == 1 && mode != YToY8)
255 env->ThrowError("PlaneToY: channel cannot be extracted from a greyscale clip!");
256
257
3/4
✓ Branch 55 → 56 taken 10 times.
✓ Branch 55 → 60 taken 9 times.
✓ Branch 56 → 57 taken 10 times.
✗ Branch 56 → 60 not taken.
19 if(YUVmode && (mode!=YToY8)){
258
1/2
✓ Branch 57 → 58 taken 10 times.
✗ Branch 57 → 79 not taken.
10 vi.height >>= vi.GetPlaneHeightSubsampling(PLANAR_U);
259
1/2
✓ Branch 58 → 59 taken 10 times.
✗ Branch 58 → 79 not taken.
10 vi.width >>= vi.GetPlaneWidthSubsampling(PLANAR_U);
260 }
261
262
8/14
✓ Branch 60 → 61 taken 19 times.
✗ Branch 60 → 67 not taken.
✓ Branch 61 → 62 taken 14 times.
✓ Branch 61 → 67 taken 5 times.
✓ Branch 62 → 63 taken 9 times.
✓ Branch 62 → 67 taken 5 times.
✓ Branch 63 → 64 taken 9 times.
✗ Branch 63 → 67 not taken.
✓ Branch 64 → 65 taken 9 times.
✗ Branch 64 → 67 not taken.
✗ Branch 65 → 66 not taken.
✓ Branch 65 → 67 taken 9 times.
✗ Branch 66 → 67 not taken.
✗ Branch 66 → 75 not taken.
19 if (mode == YToY8 || mode == UToY8 || mode == VToY8 || mode == YUY2UToY8 || mode == YUY2VToY8 || RGBmode || Alphamode)
263 {
264
3/9
✓ Branch 67 → 68 taken 19 times.
✗ Branch 67 → 79 not taken.
✓ Branch 68 → 69 taken 11 times.
✗ Branch 68 → 70 not taken.
✗ Branch 68 → 71 not taken.
✗ Branch 68 → 72 not taken.
✓ Branch 68 → 73 taken 8 times.
✗ Branch 68 → 74 not taken.
✗ Branch 68 → 75 not taken.
19 switch (vi.BitsPerComponent()) // although name is Y8, it means that greyscale stays in the same bitdepth
265 {
266 11 case 8: vi.pixel_type = VideoInfo::CS_Y8; break;
267 case 10: vi.pixel_type = VideoInfo::CS_Y10; break;
268 case 12: vi.pixel_type = VideoInfo::CS_Y12; break;
269 case 14: vi.pixel_type = VideoInfo::CS_Y14; break;
270 8 case 16: vi.pixel_type = VideoInfo::CS_Y16; break;
271 case 32: vi.pixel_type = VideoInfo::CS_Y32; break;
272 }
273 }
274 19 }
275
276 17 PVideoFrame __stdcall SwapUVToY::GetFrame(int n, IScriptEnvironment* env)
277 {
278
1/2
✓ Branch 3 → 4 taken 17 times.
✗ Branch 3 → 289 not taken.
17 PVideoFrame src = child->GetFrame(n, env);
279
1/2
✓ Branch 5 → 6 taken 17 times.
✗ Branch 5 → 287 not taken.
17 const VideoInfo& src_vi = child->GetVideoInfo();
280
281 // -----------------------------------------------------------------------
282 // Packed RGB (RGB24/32/48/64) channel extraction.
283 // Packed RGB is stored bottom-up; the Subframe offset trick used for
284 // planar formats does not apply here. We iterate rows in reverse order
285 // from the source while writing top-down into the Y-only destination.
286 // -----------------------------------------------------------------------
287
10/14
✓ Branch 6 → 7 taken 17 times.
✗ Branch 6 → 287 not taken.
✓ Branch 7 → 8 taken 9 times.
✓ Branch 7 → 13 taken 8 times.
✓ Branch 8 → 9 taken 9 times.
✗ Branch 8 → 287 not taken.
✓ Branch 9 → 10 taken 6 times.
✓ Branch 9 → 13 taken 3 times.
✓ Branch 10 → 11 taken 6 times.
✗ Branch 10 → 287 not taken.
✓ Branch 11 → 12 taken 6 times.
✗ Branch 11 → 13 not taken.
✓ Branch 14 → 15 taken 6 times.
✓ Branch 14 → 147 taken 11 times.
17 if (src_vi.IsRGB() && !src_vi.IsPlanarRGB() && !src_vi.IsPlanarRGBA()) {
288
1/4
✓ Branch 15 → 16 taken 6 times.
✗ Branch 15 → 287 not taken.
✗ Branch 276 → 277 not taken.
✗ Branch 276 → 278 not taken.
6 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
289 6 const int height = vi.height;
290 6 const int width = vi.width;
291
1/2
✓ Branch 16 → 17 taken 6 times.
✗ Branch 16 → 276 not taken.
6 const int pixelsize = src_vi.ComponentSize(); // 1 (8-bit) or 2 (16-bit)
292
1/2
✓ Branch 17 → 18 taken 6 times.
✗ Branch 17 → 276 not taken.
6 const int src_components = src_vi.NumComponents(); // 3 (RGB24/48) or 4 (RGB32/64)
293
294 // Byte offset of the requested channel within one packed pixel.
295 // Memory order: B=0, G=1, R=2, A=3 (each occupies pixelsize bytes).
296 int channel_index;
297
3/4
✓ Branch 18 → 19 taken 2 times.
✓ Branch 18 → 20 taken 2 times.
✓ Branch 18 → 21 taken 2 times.
✗ Branch 18 → 22 not taken.
6 switch (mode) {
298 2 case BToY8: channel_index = 0; break;
299 2 case GToY8: channel_index = 1; break;
300 2 case RToY8: channel_index = 2; break;
301 default /*AToY8*/: channel_index = 3; break;
302 }
303 6 const int byte_offset = channel_index * pixelsize;
304 6 const int pixel_stride = src_components * pixelsize; // bytes between adjacent pixels
305
306
1/2
✓ Branch 24 → 25 taken 6 times.
✗ Branch 24 → 276 not taken.
6 const BYTE* srcp_bottom = src->GetReadPtr()
307
1/2
✓ Branch 26 → 27 taken 6 times.
✗ Branch 26 → 276 not taken.
6 + static_cast<ptrdiff_t>(src->GetPitch()) * (height - 1);
308
1/2
✓ Branch 28 → 29 taken 6 times.
✗ Branch 28 → 276 not taken.
6 const int src_pitch = src->GetPitch();
309
1/2
✓ Branch 30 → 31 taken 6 times.
✗ Branch 30 → 276 not taken.
6 BYTE* dstp_base = dst->GetWritePtr();
310
1/2
✓ Branch 32 → 33 taken 6 times.
✗ Branch 32 → 276 not taken.
6 const int dst_pitch = dst->GetPitch();
311
312 #ifdef INTEL_INTRINSICS
313
1/2
✓ Branch 33 → 34 taken 6 times.
✗ Branch 33 → 276 not taken.
6 const bool avx2 = (env->GetCPUFlags() & CPUF_AVX2) != 0;
314
1/2
✓ Branch 34 → 35 taken 6 times.
✗ Branch 34 → 276 not taken.
6 const bool sse2 = (env->GetCPUFlags() & CPUF_SSE2) != 0;
315
6/12
✓ Branch 35 → 36 taken 6 times.
✗ Branch 35 → 41 not taken.
✓ Branch 36 → 37 taken 6 times.
✗ Branch 36 → 276 not taken.
✓ Branch 37 → 38 taken 6 times.
✗ Branch 37 → 40 not taken.
✓ Branch 38 → 39 taken 6 times.
✗ Branch 38 → 276 not taken.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 6 times.
✗ Branch 42 → 43 not taken.
✓ Branch 42 → 65 taken 6 times.
6 if (avx2 && (src_vi.IsRGB32() || src_vi.IsRGB64())) {
316 if (src_vi.IsRGB32()) {
317 switch (channel_index) {
318 case 0: extract_packed_rgb32_channel_avx2<0>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
319 case 1: extract_packed_rgb32_channel_avx2<1>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
320 case 2: extract_packed_rgb32_channel_avx2<2>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
321 case 3: extract_packed_rgb32_channel_avx2<3>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
322 }
323 } else { // RGB64
324 switch (channel_index) {
325 case 0: extract_packed_rgb64_channel_avx2<0>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
326 case 1: extract_packed_rgb64_channel_avx2<1>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
327 case 2: extract_packed_rgb64_channel_avx2<2>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
328 case 3: extract_packed_rgb64_channel_avx2<3>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
329 }
330 }
331
7/12
✓ Branch 65 → 66 taken 6 times.
✗ Branch 65 → 71 not taken.
✓ Branch 66 → 67 taken 6 times.
✗ Branch 66 → 276 not taken.
✓ Branch 67 → 68 taken 3 times.
✓ Branch 67 → 71 taken 3 times.
✓ Branch 68 → 69 taken 3 times.
✗ Branch 68 → 71 not taken.
✗ Branch 69 → 70 not taken.
✓ Branch 69 → 71 taken 3 times.
✗ Branch 72 → 73 not taken.
✓ Branch 72 → 81 taken 6 times.
6 } else if (avx2 && src_vi.IsRGB24() && channel_index <= 2 && width >= 32) {
332 // RGB24 AVX2: 32 pixels/iter; needs width >= 32 for the overlap-remainder to be valid.
333 switch (channel_index) {
334 case 0: extract_packed_rgb_noalpha_channel_avx2<uint8_t, 0>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
335 case 1: extract_packed_rgb_noalpha_channel_avx2<uint8_t, 1>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
336 case 2: extract_packed_rgb_noalpha_channel_avx2<uint8_t, 2>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
337 }
338
7/12
✓ Branch 81 → 82 taken 6 times.
✗ Branch 81 → 87 not taken.
✓ Branch 82 → 83 taken 6 times.
✗ Branch 82 → 276 not taken.
✓ Branch 83 → 84 taken 3 times.
✓ Branch 83 → 87 taken 3 times.
✓ Branch 84 → 85 taken 3 times.
✗ Branch 84 → 87 not taken.
✗ Branch 85 → 86 not taken.
✓ Branch 85 → 87 taken 3 times.
✗ Branch 88 → 89 not taken.
✓ Branch 88 → 97 taken 6 times.
6 } else if (avx2 && src_vi.IsRGB48() && channel_index <= 2 && width >= 16) {
339 // RGB48 AVX2: 16 pixels/iter; needs width >= 16 for the overlap-remainder to be valid.
340 switch (channel_index) {
341 case 0: extract_packed_rgb_noalpha_channel_avx2<uint16_t, 0>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
342 case 1: extract_packed_rgb_noalpha_channel_avx2<uint16_t, 1>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
343 case 2: extract_packed_rgb_noalpha_channel_avx2<uint16_t, 2>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
344 }
345
6/12
✓ Branch 97 → 98 taken 6 times.
✗ Branch 97 → 103 not taken.
✓ Branch 98 → 99 taken 6 times.
✗ Branch 98 → 276 not taken.
✓ Branch 99 → 100 taken 6 times.
✗ Branch 99 → 102 not taken.
✓ Branch 100 → 101 taken 6 times.
✗ Branch 100 → 276 not taken.
✗ Branch 101 → 102 not taken.
✓ Branch 101 → 103 taken 6 times.
✗ Branch 104 → 105 not taken.
✓ Branch 104 → 127 taken 6 times.
6 } else if (sse2 && (src_vi.IsRGB32() || src_vi.IsRGB64())) {
346 if (src_vi.IsRGB32()) {
347 switch (channel_index) {
348 case 0: extract_packed_rgb32_channel_sse2<0>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
349 case 1: extract_packed_rgb32_channel_sse2<1>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
350 case 2: extract_packed_rgb32_channel_sse2<2>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
351 case 3: extract_packed_rgb32_channel_sse2<3>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
352 }
353 } else { // RGB64
354 switch (channel_index) {
355 case 0: extract_packed_rgb64_channel_sse2<0>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
356 case 1: extract_packed_rgb64_channel_sse2<1>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
357 case 2: extract_packed_rgb64_channel_sse2<2>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
358 case 3: extract_packed_rgb64_channel_sse2<3>(srcp_bottom, dstp_base, src_pitch, dst_pitch, width, height); break;
359 }
360 }
361 } else
362 #endif
363 { // C fallback (RGB24/48 without AVX2, RGB32/64 without SSE2, or small widths)
364 6 const BYTE* srcp = srcp_bottom + byte_offset;
365 6 BYTE* dstp = dstp_base;
366
2/2
✓ Branch 127 → 128 taken 3 times.
✓ Branch 127 → 134 taken 3 times.
6 if (pixelsize == 1) {
367
2/2
✓ Branch 133 → 129 taken 9 times.
✓ Branch 133 → 140 taken 3 times.
12 for (int y = 0; y < height; ++y) {
368
2/2
✓ Branch 131 → 130 taken 45 times.
✓ Branch 131 → 132 taken 9 times.
54 for (int x = 0; x < width; ++x)
369 45 dstp[x] = srcp[x * pixel_stride];
370 9 srcp -= src_pitch;
371 9 dstp += dst_pitch;
372 }
373 } else { // pixelsize == 2 (RGB48 / RGB64)
374
2/2
✓ Branch 139 → 135 taken 9 times.
✓ Branch 139 → 140 taken 3 times.
12 for (int y = 0; y < height; ++y) {
375 9 uint16_t* dstp16 = reinterpret_cast<uint16_t*>(dstp);
376
2/2
✓ Branch 137 → 136 taken 27 times.
✓ Branch 137 → 138 taken 9 times.
36 for (int x = 0; x < width; ++x)
377 27 dstp16[x] = *reinterpret_cast<const uint16_t*>(srcp + x * pixel_stride);
378 9 srcp -= src_pitch;
379 9 dstp += dst_pitch;
380 }
381 }
382 }
383
384
1/2
✓ Branch 140 → 141 taken 6 times.
✗ Branch 140 → 276 not taken.
6 auto props = env->getFramePropsRW(dst);
385
1/2
✓ Branch 141 → 142 taken 6 times.
✗ Branch 141 → 276 not taken.
6 env->propDeleteKey(props, "_ChromaLocation");
386
1/2
✗ Branch 142 → 143 not taken.
✓ Branch 142 → 144 taken 6 times.
6 if (mode == AToY8)
387 env->propSetInt(props, "_ColorRange", ColorRange_Compat_e::AVS_COLORRANGE_FULL, AVSPropAppendMode::PROPAPPENDMODE_REPLACE);
388
1/2
✗ Branch 144 → 145 not taken.
✓ Branch 144 → 146 taken 6 times.
6 return dst;
389 }
390
391 11 bool NonYUY2orPackedRGBtoY8 = true;
392 int target_plane, source_plane;
393
5/8
✗ Branch 147 → 148 not taken.
✓ Branch 147 → 149 taken 4 times.
✓ Branch 147 → 150 taken 4 times.
✓ Branch 147 → 151 taken 1 time.
✓ Branch 147 → 152 taken 1 time.
✓ Branch 147 → 153 taken 1 time.
✗ Branch 147 → 154 not taken.
✗ Branch 147 → 159 not taken.
11 switch (mode) {
394 case YToY8: source_plane = PLANAR_Y; target_plane = PLANAR_Y; break;
395 4 case UToY8: source_plane = PLANAR_U; target_plane = PLANAR_Y; break;
396 4 case VToY8: source_plane = PLANAR_V; target_plane = PLANAR_Y; break;
397 1 case RToY8: source_plane = PLANAR_R; target_plane = PLANAR_G; break; // Planar RGB: GBR!
398 1 case GToY8: source_plane = PLANAR_G; target_plane = PLANAR_G; break;
399 1 case BToY8: source_plane = PLANAR_B; target_plane = PLANAR_G; break;
400 case AToY8: source_plane = PLANAR_A; target_plane = vi.IsYUVA() ? PLANAR_Y : PLANAR_G; break; // Planar RGB: GBR!
401 default: NonYUY2orPackedRGBtoY8 = false;
402 }
403
1/2
✓ Branch 160 → 161 taken 11 times.
✗ Branch 160 → 182 not taken.
11 if (NonYUY2orPackedRGBtoY8) {
404 // !! if offsets would be size_t, be cautious when you subtract two unsigned size_t variables
405
2/4
✓ Branch 162 → 163 taken 11 times.
✗ Branch 162 → 284 not taken.
✓ Branch 164 → 165 taken 11 times.
✗ Branch 164 → 284 not taken.
11 const int offset = src->GetOffset(source_plane) - src->GetOffset(target_plane); // very naughty - don't do this at home!!
406 // Abuse Subframe to snatch the U/V/R/G/B/A plane
407
5/10
✓ Branch 166 → 167 taken 11 times.
✗ Branch 166 → 284 not taken.
✓ Branch 168 → 169 taken 11 times.
✗ Branch 168 → 284 not taken.
✓ Branch 170 → 171 taken 11 times.
✗ Branch 170 → 284 not taken.
✓ Branch 171 → 172 taken 11 times.
✗ Branch 171 → 281 not taken.
✓ Branch 172 → 173 taken 11 times.
✗ Branch 172 → 279 not taken.
11 PVideoFrame sub = env->Subframe(src, offset, src->GetPitch(source_plane), src->GetRowSize(source_plane), src->GetHeight(source_plane));
408 // We have a single plane. It's safe to mod props after a subframe.
409 // Remove props that are irrelevant to a single plane.
410 // _ChromaLocation, (_Primaries, _Transfer)
411
1/2
✓ Branch 174 → 175 taken 11 times.
✗ Branch 174 → 282 not taken.
11 auto props = env->getFramePropsRW(sub);
412
1/2
✓ Branch 175 → 176 taken 11 times.
✗ Branch 175 → 282 not taken.
11 env->propDeleteKey(props, "_ChromaLocation");
413 // keep _Matrix (?) fixme: really?
414
1/2
✗ Branch 176 → 177 not taken.
✓ Branch 176 → 178 taken 11 times.
11 if (mode == AToY8) // alpha is always full range, otherwise keep source
415 env->propSetInt(props, "_ColorRange", ColorRange_Compat_e::AVS_COLORRANGE_FULL, AVSPropAppendMode::PROPAPPENDMODE_REPLACE);
416 // else we keep _ColorRange value (if any)
417
1/2
✓ Branch 178 → 179 taken 11 times.
✗ Branch 178 → 282 not taken.
11 return sub;
418 11 }
419
420 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
421 if (mode == YUY2UToY8 || mode == YUY2VToY8 || vi.IsYUY2()) {
422 const BYTE* srcp = src->GetReadPtr();
423 BYTE* dstp = dst->GetWritePtr();
424 int src_pitch = src->GetPitch();
425 int dst_pitch = dst->GetPitch();
426 int pos = (mode == YUY2UToY8 || mode == UToY) ? 1 : 3; // YUYV U=offset#1 V=offset#3
427
428 if (vi.IsYUY2()) { // YUY2 to YUY2
429 int rowsize = dst->GetRowSize();
430 #ifdef INTEL_INTRINSICS
431 if (env->GetCPUFlags() & CPUF_SSE2) {
432 yuy2_uvtoy_sse2(srcp, dstp, src_pitch, dst_pitch, rowsize, vi.height, pos);
433 return dst;
434 }
435 #endif
436
437 srcp += pos;
438 for (int y = 0; y < vi.height; ++y) {
439 for (int x = 0; x < rowsize; x += 2) {
440 dstp[x + 0] = srcp[2 * x];
441 dstp[x + 1] = 0x80;
442 }
443 srcp += src_pitch;
444 dstp += dst_pitch;
445 }
446 return dst;
447 }
448
449 // YUY2 to Y8
450
451 auto props = env->getFramePropsRW(dst);
452 env->propDeleteKey(props, "_ChromaLocation");
453
454 #ifdef INTEL_INTRINSICS
455 if (env->GetCPUFlags() & CPUF_SSE2) {
456 yuy2_uvtoy8_sse2(srcp, dstp, src_pitch, dst_pitch, vi.width, vi.height, pos);
457 return dst;
458 }
459 #endif
460 srcp += pos;
461 for (int y = 0; y < vi.height; ++y) {
462 for (int x = 0; x < vi.width; ++x) {
463 dstp[x] = srcp[x * 4];
464 }
465 srcp += src_pitch;
466 dstp += dst_pitch;
467 }
468 return dst;
469 }
470
471 // Planar to Planar. Only two modes possible UToY and VToY
472 // Copy U or V to Y and set the other chroma planes to grey
473 const int plane = mode == UToY ? PLANAR_U : PLANAR_V;
474 env->BitBlt(dst->GetWritePtr(PLANAR_Y), dst->GetPitch(PLANAR_Y), src->GetReadPtr(plane),
475 src->GetPitch(plane), src->GetRowSize(plane), src->GetHeight(plane));
476
477 // Clear chroma
478 int pitch = dst->GetPitch(PLANAR_U);
479 int height = dst->GetHeight(PLANAR_U);
480 int rowsize = dst->GetRowSize(PLANAR_U);
481 BYTE* dstp_u = dst->GetWritePtr(PLANAR_U);
482 BYTE* dstp_v = dst->GetWritePtr(PLANAR_V);
483
484 if (vi.ComponentSize() == 1) { // 8bit
485 fill_chroma<BYTE>(dstp_u, dstp_v, height, rowsize, pitch, 0x80);
486 }
487 else if (vi.ComponentSize() == 2) { // 16bit
488 uint16_t grey_val = 1 << (vi.BitsPerComponent() - 1); // 0x8000 for 16 bit
489 fill_chroma<uint16_t>(dstp_u, dstp_v, height, rowsize, pitch, grey_val);
490 }
491 else { // 32bit(float)
492 float grey_val = uv8tof(128);
493 fill_chroma<float>(dstp_u, dstp_v, height, rowsize, pitch, grey_val);
494 }
495
496 return dst;
497 17 }
498
499
500 AVSValue __cdecl SwapYToUV::CreateYToUV(AVSValue args, void* , IScriptEnvironment* env)
501 {
502 return new SwapYToUV(args[0].AsClip(), args[1].AsClip(), NULL , NULL, env);
503 }
504
505 AVSValue __cdecl SwapYToUV::CreateYToYUV(AVSValue args, void* , IScriptEnvironment* env)
506 {
507 return new SwapYToUV(args[0].AsClip(), args[1].AsClip(), args[2].AsClip(), NULL, env);
508 }
509
510 AVSValue __cdecl SwapYToUV::CreateYToYUVA(AVSValue args, void* , IScriptEnvironment* env)
511 {
512 return new SwapYToUV(args[0].AsClip(), args[1].AsClip(), args[2].AsClip(), args[3].AsClip(), env);
513 }
514
515 3 SwapYToUV::SwapYToUV(PClip _child, PClip _clip, PClip _clipY, PClip _clipA, IScriptEnvironment* env)
516
5/10
✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 132 not taken.
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 130 not taken.
✓ Branch 5 → 6 taken 3 times.
✗ Branch 5 → 139 not taken.
✓ Branch 6 → 7 taken 3 times.
✗ Branch 6 → 137 not taken.
✓ Branch 7 → 8 taken 3 times.
✗ Branch 7 → 135 not taken.
3 : GenericVideoFilter(_child), clip(_clip), clipY(_clipY), clipA(_clipA)
517 {
518
5/12
✓ Branch 8 → 9 taken 3 times.
✗ Branch 8 → 133 not taken.
✓ Branch 9 → 10 taken 3 times.
✗ Branch 9 → 15 not taken.
✓ Branch 10 → 11 taken 3 times.
✗ Branch 10 → 133 not taken.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 15 taken 3 times.
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 15 not taken.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 3 times.
3 if(!(vi.IsYUVA() || vi.IsY()) && clipA)
519 env->ThrowError("YToUV: Only Y or YUVA data accepted when alpha clip is provided"); // Y, YUV and YUY2
520
3/10
✓ Branch 18 → 19 taken 3 times.
✗ Branch 18 → 133 not taken.
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 23 taken 3 times.
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 133 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 3 times.
3 if (!vi.IsYUV() && !vi.IsYUVA())
521 {
522 env->ThrowError("YToUV: Only YUV or YUVA data accepted"); // Y, YUV and YUY2
523 }
524
525
1/2
✓ Branch 27 → 28 taken 3 times.
✗ Branch 27 → 133 not taken.
3 const VideoInfo& vi2 = clip->GetVideoInfo();
526
1/2
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 30 taken 3 times.
3 if (vi.height != vi2.height)
527 env->ThrowError("YToUV: Clips do not have the same height (U & V mismatch) !");
528
1/2
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 3 times.
3 if (vi.width != vi2.width)
529 env->ThrowError("YToUV: Clips do not have the same width (U & V mismatch) !");
530
3/6
✓ Branch 32 → 33 taken 3 times.
✗ Branch 32 → 133 not taken.
✓ Branch 33 → 34 taken 3 times.
✗ Branch 33 → 133 not taken.
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 36 taken 3 times.
3 if (vi.IsYUY2() != vi2.IsYUY2())
531 env->ThrowError("YToUV: YUY2 Clips must have same colorspace (U & V mismatch) !");
532
533 // no third parameter: no Y clip
534
2/2
✓ Branch 37 → 38 taken 1 time.
✓ Branch 37 → 56 taken 2 times.
3 if (!clipY) {
535
2/4
✓ Branch 38 → 39 taken 1 time.
✗ Branch 38 → 133 not taken.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 1 time.
1 if (vi.IsYUY2())
536 vi.width *= 2;
537
2/4
✓ Branch 41 → 42 taken 1 time.
✗ Branch 41 → 133 not taken.
✓ Branch 42 → 43 taken 1 time.
✗ Branch 42 → 52 not taken.
1 else if (vi.IsY()) {
538
2/9
✓ Branch 43 → 44 taken 1 time.
✗ Branch 43 → 133 not taken.
✓ Branch 44 → 45 taken 1 time.
✗ Branch 44 → 46 not taken.
✗ Branch 44 → 47 not taken.
✗ Branch 44 → 48 not taken.
✗ Branch 44 → 49 not taken.
✗ Branch 44 → 50 not taken.
✗ Branch 44 → 51 not taken.
1 switch(vi.BitsPerComponent()) {
539 1 case 8: vi.pixel_type = VideoInfo::CS_YV24; break;
540 case 10: vi.pixel_type = VideoInfo::CS_YUV444P10; break;
541 case 12: vi.pixel_type = VideoInfo::CS_YUV444P12; break;
542 case 14: vi.pixel_type = VideoInfo::CS_YUV444P14; break;
543 case 16: vi.pixel_type = VideoInfo::CS_YUV444P16; break;
544 case 32: vi.pixel_type = VideoInfo::CS_YUV444PS; break;
545 }
546 }
547 else {
548 vi.height <<= vi.GetPlaneHeightSubsampling(PLANAR_U);
549 vi.width <<= vi.GetPlaneWidthSubsampling(PLANAR_U);
550 }
551 1 return;
552 }
553
554 // Y clip parameter exists, Y channel will be copied from that
555
1/2
✓ Branch 57 → 58 taken 2 times.
✗ Branch 57 → 133 not taken.
2 const VideoInfo& vi3 = clipY->GetVideoInfo();
556
3/6
✓ Branch 58 → 59 taken 2 times.
✗ Branch 58 → 133 not taken.
✓ Branch 59 → 60 taken 2 times.
✗ Branch 59 → 133 not taken.
✗ Branch 60 → 61 not taken.
✓ Branch 60 → 62 taken 2 times.
2 if (vi.IsYUY2() != vi3.IsYUY2())
557 env->ThrowError("YToUV: YUY2 Clips must have same colorspace (UV & Y mismatch) !");
558
559
2/4
✓ Branch 62 → 63 taken 2 times.
✗ Branch 62 → 133 not taken.
✗ Branch 63 → 64 not taken.
✓ Branch 63 → 69 taken 2 times.
2 if (vi.IsYUY2()) {
560 if (vi3.height != vi.height)
561 env->ThrowError("YToUV: Y clip does not have the same height of the UV clips! (YUY2 mode)");
562 vi.width *= 2;
563 if (vi3.width != vi.width)
564 env->ThrowError("YToUV: Y clip does not have the double width of the UV clips!");
565 return;
566 }
567
568
2/2
✓ Branch 70 → 71 taken 1 time.
✓ Branch 70 → 83 taken 1 time.
2 if (clipA) {
569
2/4
✓ Branch 71 → 72 taken 1 time.
✗ Branch 71 → 133 not taken.
✗ Branch 72 → 73 not taken.
✓ Branch 72 → 74 taken 1 time.
1 if(vi.IsYUY2())
570 env->ThrowError("YToUV: YUY2 not supported with alpha clip");
571
1/2
✓ Branch 75 → 76 taken 1 time.
✗ Branch 75 → 133 not taken.
1 const VideoInfo& vi4 = clipA->GetVideoInfo();
572
2/4
✓ Branch 76 → 77 taken 1 time.
✗ Branch 76 → 78 not taken.
✗ Branch 77 → 78 not taken.
✓ Branch 77 → 79 taken 1 time.
1 if (vi4.width != vi3.width || vi4.height != vi3.height) // Y width == A width
573 env->ThrowError("YToUV: different Y and A clip dimensions");
574
3/6
✓ Branch 79 → 80 taken 1 time.
✗ Branch 79 → 133 not taken.
✓ Branch 80 → 81 taken 1 time.
✗ Branch 80 → 133 not taken.
✗ Branch 81 → 82 not taken.
✓ Branch 81 → 83 taken 1 time.
1 if(vi4.BitsPerComponent() != vi3.BitsPerComponent())
575 env->ThrowError("YToUV: different Y and A clip bit depth");
576 }
577
578 // Autogenerate destination colorformat
579
2/9
✓ Branch 83 → 84 taken 2 times.
✗ Branch 83 → 133 not taken.
✓ Branch 84 → 85 taken 2 times.
✗ Branch 84 → 90 not taken.
✗ Branch 84 → 95 not taken.
✗ Branch 84 → 100 not taken.
✗ Branch 84 → 105 not taken.
✗ Branch 84 → 110 not taken.
✗ Branch 84 → 115 not taken.
2 switch (vi.BitsPerComponent())
580 { // CS_Sub_Width_2 and CS_Sub_Height_2 are 0, vi bitfield can or'd if change needed
581
2/2
✓ Branch 86 → 87 taken 1 time.
✓ Branch 86 → 88 taken 1 time.
2 case 8: vi.pixel_type = clipA ? VideoInfo::CS_YUVA420 : vi.pixel_type = VideoInfo::CS_YV12; break;
582 case 10: vi.pixel_type = clipA ? VideoInfo::CS_YUVA420P10 : vi.pixel_type = VideoInfo::CS_YUV420P10; break;
583 case 12: vi.pixel_type = clipA ? VideoInfo::CS_YUVA420P12 : vi.pixel_type = VideoInfo::CS_YUV420P12; break;
584 case 14: vi.pixel_type = clipA ? VideoInfo::CS_YUVA420P14 : VideoInfo::CS_YUV420P14; break;
585 case 16: vi.pixel_type = clipA ? VideoInfo::CS_YUVA420P16 : VideoInfo::CS_YUV420P16; break;
586 case 32: vi.pixel_type = clipA ? VideoInfo::CS_YUVA420PS : VideoInfo::CS_YUV420PS; break;
587 }
588
589
1/2
✓ Branch 115 → 116 taken 2 times.
✗ Branch 115 → 117 not taken.
2 if (vi3.width == vi.width) // Y width == U width -> subsampling 1:1
590 2 vi.pixel_type |= VideoInfo::CS_Sub_Width_1;
591 else if (vi3.width == vi.width * 2) // Y width == U width*2 -> horiz. subsampling 2
592 vi.width *= 2; // YV12 subsampling CS_Sub_Width_2 is o.k.
593 else if (vi3.width == vi.width * 4) { // Y width == U width*4 -> horiz. subsampling 4
594 vi.pixel_type |= VideoInfo::CS_Sub_Width_4;
595 vi.width *= 4; // final clip width is 3x of the U channel width
596 }
597 else
598 env->ThrowError("YToUV: Video width ratio does not match any internal colorspace.");
599
600
1/2
✓ Branch 122 → 123 taken 2 times.
✗ Branch 122 → 124 not taken.
2 if (vi3.height == vi.height)
601 2 vi.pixel_type |= VideoInfo::CS_Sub_Height_1;
602 else if (vi3.height == vi.height * 2)
603 vi.height *= 2;
604 else if (vi3.height == vi.height * 4) {
605 vi.pixel_type |= VideoInfo::CS_Sub_Height_4;
606 vi.height *= 4;
607 }
608 else
609 env->ThrowError("YToUV: Video height ratio does not match any internal colorspace.");
610 }
611
612 template <bool has_clipY>
613 static void yuy2_ytouv_c(const BYTE* src_y, const BYTE* src_u, const BYTE* src_v, BYTE* dstp, int pitch_y, int pitch_u, int pitch_v, int dst_pitch, int dst_rowsize, int height)
614 {
615 for (int y = 0; y < height; ++y) {
616 for (int x = 0; x < dst_rowsize; x += 4) {
617 dstp[x + 0] = has_clipY ? src_y[x] : 0x7e;
618 dstp[x + 1] = src_u[x / 2];
619 dstp[x + 2] = has_clipY ? src_y[x + 2] : 0x7e;
620 dstp[x + 3] = src_v[x / 2];
621 }
622 src_y += pitch_y;
623 src_u += pitch_u;
624 src_v += pitch_v;
625 dstp += dst_pitch;
626 }
627 }
628
629 PVideoFrame __stdcall SwapYToUV::GetFrame(int n, IScriptEnvironment* env) {
630 PVideoFrame src = child->GetFrame(n, env);
631 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
632
633 if (vi.IsYUY2()) {
634 const BYTE* srcp_u = src->GetReadPtr();
635 const int pitch_u = src->GetPitch();
636
637 PVideoFrame srcv = clip->GetFrame(n, env);
638 const BYTE* srcp_v = srcv->GetReadPtr();
639 const int pitch_v = srcv->GetPitch();
640
641 BYTE* dstp = dst->GetWritePtr();
642 const int rowsize = dst->GetRowSize();
643 const int dst_pitch = dst->GetPitch();
644
645 if (clipY) {
646 PVideoFrame srcy = clipY->GetFrame(n, env);
647 const BYTE* srcp_y = srcy->GetReadPtr();
648 const int pitch_y = srcy->GetPitch();
649 #ifdef INTEL_INTRINSICS
650 if (env->GetCPUFlags() & CPUF_SSE2)
651 yuy2_ytouv_sse2<true>(srcp_y, srcp_u, srcp_v, dstp, pitch_y, pitch_u, pitch_v, dst_pitch, rowsize, vi.height);
652 else
653 #endif
654 yuy2_ytouv_c<true>(srcp_y, srcp_u, srcp_v, dstp, pitch_y, pitch_u, pitch_v, dst_pitch, rowsize, vi.height);
655 }
656 else
657 yuy2_ytouv_c<false>(nullptr, srcp_u, srcp_v, dstp, 0, pitch_u, pitch_v, dst_pitch, rowsize, vi.height);
658
659 return dst;
660 }
661
662 // Planar:
663 env->BitBlt(dst->GetWritePtr(PLANAR_U), dst->GetPitch(PLANAR_U),
664 src->GetReadPtr(PLANAR_Y), src->GetPitch(PLANAR_Y), src->GetRowSize(PLANAR_Y), src->GetHeight(PLANAR_Y));
665
666 src = clip->GetFrame(n, env);
667 env->BitBlt(dst->GetWritePtr(PLANAR_V), dst->GetPitch(PLANAR_V),
668 src->GetReadPtr(PLANAR_Y), src->GetPitch(PLANAR_Y), src->GetRowSize(PLANAR_Y), src->GetHeight(PLANAR_Y));
669
670 if (clipA) {
671 int source_plane = (clipA->GetVideoInfo().IsPlanarRGBA() ||
672 clipA->GetVideoInfo().IsYUVA()) ? PLANAR_A : PLANAR_Y;
673 src = clipA->GetFrame(n, env);
674 env->BitBlt(dst->GetWritePtr(PLANAR_A), dst->GetPitch(PLANAR_A),
675 src->GetReadPtr(source_plane), src->GetPitch(source_plane), src->GetRowSize(source_plane), src->GetHeight(source_plane));
676 }
677
678 if (clipY) {
679 src = clipY->GetFrame(n, env);
680 env->BitBlt(dst->GetWritePtr(PLANAR_Y), dst->GetPitch(PLANAR_Y),
681 src->GetReadPtr(PLANAR_Y), src->GetPitch(PLANAR_Y), src->GetRowSize(PLANAR_Y), src->GetHeight(PLANAR_Y));
682 return dst;
683 }
684
685 // if no Y script was given, fill Y plane with neutral value
686 // Luma = 126 (0x7e)
687 BYTE* dstp = dst->GetWritePtr(PLANAR_Y);
688 int rowsize = dst->GetRowSize(PLANAR_Y);
689 int pitch = dst->GetPitch(PLANAR_Y);
690
691 if (vi.ComponentSize() == 1) // 8bit
692 fill_plane<BYTE>(dstp, vi.height, rowsize, pitch, 0x7e);
693 else if (vi.ComponentSize() == 2) { // 16bit
694 uint16_t luma_val = 0x7e << (vi.BitsPerComponent() - 8);
695 fill_plane<uint16_t>(dstp, vi.height, rowsize, pitch, luma_val);
696 }
697 else { // 32bit(float)
698 fill_plane<float>(dstp, vi.height, rowsize, pitch, 126.0f / 256);
699 }
700
701 return dst;
702 }
703
704 // AVS+: Combine planes free-style for all planar formats
705 AVSValue __cdecl CombinePlanes::CreateCombinePlanes(AVSValue args, void* user_data, IScriptEnvironment* env)
706 {
707 int mode = (int)(intptr_t)(user_data);
708 int target_planes_param = 0 + mode;
709 int source_planes_param = 1 + mode;
710 int pixel_type_param = 2 + mode;
711 int sample_clip_param = 3 + mode;
712
713 bool hasSampleClip = args[sample_clip_param].Defined();
714
715 return new CombinePlanes(args[0].AsClip(),
716 mode >= 2 ? args[1].AsClip() : nullptr,
717 mode >= 3 ? args[2].AsClip() : nullptr,
718 mode >= 4 ? args[3].AsClip() : nullptr,
719 hasSampleClip ? args[sample_clip_param].AsClip() : nullptr,
720 args[target_planes_param].AsString(""),
721 args[source_planes_param].AsString(""),
722 args[pixel_type_param].AsString(""),
723 env);
724 }
725
726 6 CombinePlanes::CombinePlanes(PClip _child, PClip _clip2, PClip _clip3, PClip _clip4, PClip _sample,
727 6 const char *_target_planes_str, const char *_source_planes_str, const char *_pixel_type, IScriptEnvironment* env)
728
6/14
✓ Branch 2 → 3 taken 6 times.
✗ Branch 2 → 242 not taken.
✓ Branch 3 → 4 taken 6 times.
✗ Branch 3 → 240 not taken.
✓ Branch 6 → 7 taken 24 times.
✗ Branch 6 → 243 not taken.
✓ Branch 8 → 6 taken 24 times.
✓ Branch 8 → 9 taken 6 times.
✗ Branch 243 → 244 not taken.
✗ Branch 243 → 247 not taken.
✗ Branch 245 → 246 not taken.
✗ Branch 245 → 247 not taken.
✓ Branch 265 → 266 taken 4 times.
✗ Branch 265 → 270 not taken.
50 : GenericVideoFilter(_child)
729 {
730
1/2
✓ Branch 9 → 10 taken 6 times.
✗ Branch 9 → 264 not taken.
6 clips[0] = _child;
731
1/2
✓ Branch 10 → 11 taken 6 times.
✗ Branch 10 → 264 not taken.
6 clips[1] = _clip2;
732
1/2
✓ Branch 11 → 12 taken 6 times.
✗ Branch 11 → 264 not taken.
6 clips[2] = _clip3;
733
1/2
✓ Branch 12 → 13 taken 6 times.
✗ Branch 12 → 264 not taken.
6 clips[3] = _clip4;
734 // planes(_planes), pixel_type(pixel_type)
735 // getting target video format
736 VideoInfo vi_default;
737 6 memset(&vi_default, 0, sizeof(VideoInfo));
738
739 6 bool videoFormatOverridden = false;
740
741
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 18 taken 6 times.
6 if (_sample) {
742 vi_default = _sample->GetVideoInfo();
743 videoFormatOverridden = true;
744 }
745 else { // no sample video: format from first clip
746
1/2
✓ Branch 19 → 20 taken 6 times.
✗ Branch 19 → 264 not taken.
6 vi_default = child->GetVideoInfo();
747 }
748 // 1.) sample clip 2.) first clip 3.) pixel_type override
749 // 4.) when input clips are greyscale, automatically use YUV(A)/RGB(A) depending on "planes" string
750
2/2
✓ Branch 21 → 22 taken 1 time.
✓ Branch 21 → 26 taken 5 times.
6 if (*_pixel_type) {
751
1/2
✓ Branch 22 → 23 taken 1 time.
✗ Branch 22 → 264 not taken.
1 int i_pixel_type = GetPixelTypeFromName(_pixel_type);
752
1/2
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 1 time.
1 if (i_pixel_type == VideoInfo::CS_UNKNOWN)
753 env->ThrowError("CombinePlanes: unknown pixel_type %s", _pixel_type);
754 1 vi_default.pixel_type = i_pixel_type;
755 1 videoFormatOverridden = true;
756 }
757
758
2/4
✓ Branch 26 → 27 taken 6 times.
✗ Branch 26 → 264 not taken.
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 6 times.
6 if (!vi_default.IsPlanar())
759 env->ThrowError("CombinePlanes: output clip video format is not planar!");
760
761 // autoconvert packed RGB or YUY2 inputs, in order to able to extract planes
762
2/2
✓ Branch 64 → 30 taken 24 times.
✓ Branch 64 → 65 taken 6 times.
30 for (int i = 0; i < 4; i++) {
763
2/2
✓ Branch 31 → 32 taken 13 times.
✓ Branch 31 → 33 taken 11 times.
24 if (!clips[i]) continue;
764
1/2
✓ Branch 34 → 35 taken 11 times.
✗ Branch 34 → 264 not taken.
11 const VideoInfo &vi_test = clips[i]->GetVideoInfo();
765
3/10
✓ Branch 35 → 36 taken 11 times.
✗ Branch 35 → 264 not taken.
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 40 taken 11 times.
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 264 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 40 not taken.
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 51 taken 11 times.
11 if (vi_test.IsRGB() && !vi_test.IsPlanar()) {
766 bool hasAlpha = vi_test.NumComponents() == 4;
767 clips[i] = new PackedRGBtoPlanarRGB(clips[i], hasAlpha, hasAlpha);
768 }
769
2/4
✓ Branch 51 → 52 taken 11 times.
✗ Branch 51 → 264 not taken.
✗ Branch 52 → 53 not taken.
✓ Branch 52 → 63 taken 11 times.
11 else if (vi_test.IsYUY2()) {
770 AVSValue emptyValue;
771 clips[i] = new ConvertYUY2ToYV16_or_Y(clips[i], false /*to_y*/, env);
772 }
773 }
774
775 6 int source_plane_count = (int)strlen(_source_planes_str); // no check here, can be 0
776 6 int target_plane_count = (int)strlen(_target_planes_str);
777
1/2
✗ Branch 65 → 66 not taken.
✓ Branch 65 → 67 taken 6 times.
6 if (target_plane_count == 0)
778 env->ThrowError("CombinePlanes: no target planes given!");
779
5/6
✓ Branch 68 → 69 taken 6 times.
✗ Branch 68 → 76 not taken.
✓ Branch 70 → 71 taken 4 times.
✓ Branch 70 → 75 taken 2 times.
✓ Branch 72 → 73 taken 1 time.
✓ Branch 72 → 74 taken 3 times.
6 int clip_count = clips[3] ? 4 : clips[2] ? 3 : clips[1] ? 2 : 1;
780
2/2
✓ Branch 77 → 78 taken 1 time.
✓ Branch 77 → 79 taken 5 times.
6 if (target_plane_count < clip_count)
781
1/2
✗ Branch 78 → 79 not taken.
✓ Branch 78 → 264 taken 1 time.
1 env->ThrowError("CombinePlanes: more clips specified than target planes");
782
783 // If no video format was forced and no input planes were given
784 // and all the source clips are Y, then
785 // we give it a try of easy greyscale->RGB(A) or YUV(A) conversion
786 // depending on the _target_planes_str
787 5 bool allIsGrey = true;
788
2/2
✓ Branch 86 → 80 taken 8 times.
✓ Branch 86 → 87 taken 4 times.
12 for (int i = 0; i < clip_count; i++) {
789
4/6
✓ Branch 81 → 82 taken 8 times.
✗ Branch 81 → 264 not taken.
✓ Branch 82 → 83 taken 8 times.
✗ Branch 82 → 264 not taken.
✓ Branch 83 → 84 taken 1 time.
✓ Branch 83 → 85 taken 7 times.
8 if (!clips[i]->GetVideoInfo().IsY()) {
790 1 allIsGrey = false;
791 1 break;
792 }
793 }
794
795
4/4
✓ Branch 87 → 88 taken 4 times.
✓ Branch 87 → 113 taken 1 time.
✓ Branch 88 → 89 taken 3 times.
✓ Branch 88 → 113 taken 1 time.
5 if (!videoFormatOverridden && source_plane_count == 0) {
796
1/2
✓ Branch 89 → 90 taken 3 times.
✗ Branch 89 → 113 not taken.
3 if (allIsGrey) {
797 // special case. Figure out RGB(A) or YUV(A) or Y
798 3 bool allIsYUV = true;
799 3 bool allIsRGB = true;
800
2/2
✓ Branch 100 → 91 taken 8 times.
✓ Branch 100 → 101 taken 3 times.
11 for (int i = 0; i < target_plane_count; i++) {
801 8 char ch = toupper(_target_planes_str[i]);
802
3/6
✓ Branch 91 → 92 taken 8 times.
✗ Branch 91 → 94 not taken.
✓ Branch 92 → 93 taken 8 times.
✗ Branch 92 → 94 not taken.
✗ Branch 93 → 94 not taken.
✓ Branch 93 → 95 taken 8 times.
8 if (ch == 'R' || ch == 'G' || ch == 'B') allIsYUV = false;
803
6/6
✓ Branch 95 → 96 taken 5 times.
✓ Branch 95 → 98 taken 3 times.
✓ Branch 96 → 97 taken 3 times.
✓ Branch 96 → 98 taken 2 times.
✓ Branch 97 → 98 taken 2 times.
✓ Branch 97 → 99 taken 1 time.
8 if (ch == 'Y' || ch == 'U' || ch == 'V') allIsRGB = false;
804 }
805
1/4
✗ Branch 101 → 102 not taken.
✓ Branch 101 → 103 taken 3 times.
✗ Branch 102 → 103 not taken.
✗ Branch 102 → 113 not taken.
3 if (allIsYUV || allIsRGB) {
806 int new_pixel_type;
807
1/2
✗ Branch 103 → 104 not taken.
✓ Branch 103 → 107 taken 3 times.
3 if (allIsRGB)
808 new_pixel_type = target_plane_count == 4 ? VideoInfo::CS_GENERIC_RGBAP : VideoInfo::CS_GENERIC_RGBP;
809 else // if (allIsYUV)
810
1/2
✗ Branch 107 → 108 not taken.
✓ Branch 107 → 109 taken 3 times.
3 new_pixel_type = target_plane_count == 4 ? VideoInfo::CS_GENERIC_YUVA444 : VideoInfo::CS_GENERIC_YUV444;
811
1/2
✓ Branch 111 → 112 taken 3 times.
✗ Branch 111 → 264 not taken.
3 int bits_mask = clips[0]->GetVideoInfo().pixel_type & VideoInfo::CS_Sample_Bits_Mask;
812 3 new_pixel_type |= bits_mask; // copy bit-depth from the first clip
813 3 vi_default.pixel_type = new_pixel_type;
814 }
815 }
816 }
817
818 5 vi = vi_default;
819
820
2/4
✓ Branch 113 → 114 taken 5 times.
✗ Branch 113 → 264 not taken.
✗ Branch 114 → 115 not taken.
✓ Branch 114 → 116 taken 5 times.
5 if(!vi_default.IsPlanar())
821 env->ThrowError("CombinePlanes: target format must be planar!");
822
823
3/4
✓ Branch 116 → 117 taken 5 times.
✗ Branch 116 → 264 not taken.
✓ Branch 117 → 118 taken 1 time.
✓ Branch 117 → 120 taken 4 times.
5 if(target_plane_count > vi_default.NumComponents())
824
2/4
✓ Branch 118 → 119 taken 1 time.
✗ Branch 118 → 264 not taken.
✗ Branch 119 → 120 not taken.
✓ Branch 119 → 264 taken 1 time.
1 env->ThrowError("CombinePlanes: too many target planes (%d)! Target video plane count is %d!", target_plane_count, vi_default.NumComponents());
825
826
3/4
✓ Branch 120 → 121 taken 1 time.
✓ Branch 120 → 123 taken 3 times.
✗ Branch 121 → 122 not taken.
✓ Branch 121 → 123 taken 1 time.
4 if(source_plane_count != 0 && source_plane_count != target_plane_count)
827 env->ThrowError("CombinePlanes: source plane count must match with target plane count if provided!");
828
829 // useful for later check
830
2/8
✓ Branch 123 → 124 taken 4 times.
✗ Branch 123 → 264 not taken.
✗ Branch 124 → 125 not taken.
✓ Branch 124 → 127 taken 4 times.
✗ Branch 125 → 126 not taken.
✗ Branch 125 → 264 not taken.
✗ Branch 126 → 127 not taken.
✗ Branch 126 → 128 not taken.
4 bool targetIsYUV = vi_default.IsYUV() || vi_default.IsYUVA();
831
4/8
✓ Branch 129 → 130 taken 4 times.
✗ Branch 129 → 264 not taken.
✓ Branch 130 → 131 taken 4 times.
✗ Branch 130 → 133 not taken.
✓ Branch 131 → 132 taken 4 times.
✗ Branch 131 → 264 not taken.
✗ Branch 132 → 133 not taken.
✓ Branch 132 → 134 taken 4 times.
4 bool targetHasAlpha = vi_default.IsYUVA() || vi_default.IsPlanarRGBA();
832
1/2
✓ Branch 135 → 136 taken 4 times.
✗ Branch 135 → 264 not taken.
4 bool targetIsY = vi_default.IsY();
833
834 // class variables
835
1/2
✓ Branch 136 → 137 taken 4 times.
✗ Branch 136 → 264 not taken.
4 bits_per_pixel = vi_default.BitsPerComponent();
836
1/2
✓ Branch 137 → 138 taken 4 times.
✗ Branch 137 → 264 not taken.
4 pixelsize = vi_default.ComponentSize();
837 4 planecount = target_plane_count;
838
839 // if source plane is given, use it otherwise assume these
840 4 const char * rgb_source_planes_str_def = "RGBA";
841
2/2
✓ Branch 138 → 139 taken 3 times.
✓ Branch 138 → 140 taken 1 time.
4 const char * yuv_source_planes_str_def = allIsGrey ? "YYYY" : "YUVA";
842
843 4 int last_clip_index = 0;
844
2/2
✓ Branch 238 → 142 taken 10 times.
✓ Branch 238 → 239 taken 2 times.
12 for (int i = 0; i < target_plane_count; i++) {
845 10 char ch = toupper(_target_planes_str[i]);
846
3/6
✓ Branch 142 → 143 taken 10 times.
✗ Branch 142 → 145 not taken.
✓ Branch 143 → 144 taken 10 times.
✗ Branch 143 → 145 not taken.
✗ Branch 144 → 145 not taken.
✓ Branch 144 → 146 taken 10 times.
10 bool isRGB = ch == 'R' || ch == 'G' || ch == 'B';
847
6/6
✓ Branch 147 → 148 taken 6 times.
✓ Branch 147 → 150 taken 4 times.
✓ Branch 148 → 149 taken 3 times.
✓ Branch 148 → 150 taken 3 times.
✓ Branch 149 → 150 taken 2 times.
✓ Branch 149 → 151 taken 1 time.
10 bool isYUV = ch == 'Y' || ch == 'U' || ch == 'V';
848 10 bool isAlpha = ch == 'A';
849
4/6
✓ Branch 152 → 153 taken 10 times.
✗ Branch 152 → 156 not taken.
✓ Branch 153 → 154 taken 1 time.
✓ Branch 153 → 156 taken 9 times.
✓ Branch 154 → 155 taken 1 time.
✗ Branch 154 → 156 not taken.
10 if(!isRGB && !isYUV && !isAlpha)
850
1/2
✗ Branch 155 → 156 not taken.
✓ Branch 155 → 263 taken 1 time.
1 env->ThrowError("CombinePlanes: invalid plane definifion :%s", planes);
851
6/16
✓ Branch 156 → 157 taken 9 times.
✗ Branch 156 → 158 not taken.
✓ Branch 157 → 158 taken 9 times.
✗ Branch 157 → 164 not taken.
✗ Branch 158 → 159 not taken.
✓ Branch 158 → 160 taken 9 times.
✗ Branch 159 → 160 not taken.
✗ Branch 159 → 164 not taken.
✓ Branch 160 → 161 taken 9 times.
✗ Branch 160 → 162 not taken.
✓ Branch 161 → 162 taken 9 times.
✗ Branch 161 → 164 not taken.
✗ Branch 162 → 163 not taken.
✓ Branch 162 → 165 taken 9 times.
✗ Branch 163 → 164 not taken.
✗ Branch 163 → 165 not taken.
9 if((targetIsYUV && isRGB) || (!targetIsYUV && isYUV) || (!targetHasAlpha && isAlpha) || (targetIsY && ch!='Y'))
852 env->ThrowError("CombinePlanes: target has no such plane %c", ch);
853
854 int current_target_plane;
855
3/8
✗ Branch 165 → 166 not taken.
✗ Branch 165 → 167 not taken.
✗ Branch 165 → 168 not taken.
✗ Branch 165 → 169 not taken.
✓ Branch 165 → 170 taken 4 times.
✓ Branch 165 → 171 taken 3 times.
✓ Branch 165 → 172 taken 2 times.
✗ Branch 165 → 173 not taken.
9 switch (ch) {
856 case 'R': current_target_plane = PLANAR_R; break;
857 case 'G': current_target_plane = PLANAR_G; break;
858 case 'B': current_target_plane = PLANAR_B; break;
859 case 'A': current_target_plane = PLANAR_A; break;
860 4 case 'Y': current_target_plane = PLANAR_Y; break;
861 3 case 'U': current_target_plane = PLANAR_U; break;
862 2 case 'V': current_target_plane = PLANAR_V; break;
863 }
864 9 target_planes[i] = current_target_plane;
865
1/2
✓ Branch 173 → 174 taken 9 times.
✗ Branch 173 → 263 not taken.
9 int target_plane_width = vi_default.width >> vi_default.GetPlaneWidthSubsampling(current_target_plane);
866
1/2
✓ Branch 174 → 175 taken 9 times.
✗ Branch 174 → 263 not taken.
9 int target_plane_height = vi_default.height >> vi_default.GetPlaneHeightSubsampling(current_target_plane);
867
868
2/2
✓ Branch 176 → 177 taken 7 times.
✓ Branch 176 → 178 taken 2 times.
9 if (clips[i]) // source clip count can be less than target planes count
869 7 last_clip_index = i; // last defined clip is used for the others
870
871 // check source clips and optinally their plane order
872
1/2
✓ Branch 179 → 180 taken 9 times.
✗ Branch 179 → 263 not taken.
9 VideoInfo src_vi = clips[last_clip_index]->GetVideoInfo();
873
874
2/4
✓ Branch 180 → 181 taken 9 times.
✗ Branch 180 → 263 not taken.
✗ Branch 181 → 182 not taken.
✓ Branch 181 → 183 taken 9 times.
9 if(src_vi.BitsPerComponent() != bits_per_pixel)
875 env->ThrowError("CombinePlanes: source bit depth is different from %d", bits_per_pixel);
876
877
2/8
✓ Branch 183 → 184 taken 9 times.
✗ Branch 183 → 263 not taken.
✗ Branch 184 → 185 not taken.
✓ Branch 184 → 187 taken 9 times.
✗ Branch 185 → 186 not taken.
✗ Branch 185 → 263 not taken.
✗ Branch 186 → 187 not taken.
✗ Branch 186 → 188 not taken.
9 bool sourceIsYUV = src_vi.IsYUV() || src_vi.IsYUVA();
878
4/8
✓ Branch 189 → 190 taken 9 times.
✗ Branch 189 → 263 not taken.
✓ Branch 190 → 191 taken 9 times.
✗ Branch 190 → 193 not taken.
✓ Branch 191 → 192 taken 9 times.
✗ Branch 191 → 263 not taken.
✗ Branch 192 → 193 not taken.
✓ Branch 192 → 194 taken 9 times.
9 bool sourceHasAlpha = src_vi.IsYUVA() || src_vi.IsPlanarRGBA();
879
1/2
✓ Branch 195 → 196 taken 9 times.
✗ Branch 195 → 263 not taken.
9 bool sourceIsY = src_vi.IsY();
880 // check source
881 // source_plane_count is either 0 or == target_plane_count
882 {
883 char ch;
884
2/2
✓ Branch 196 → 197 taken 3 times.
✓ Branch 196 → 198 taken 6 times.
9 if (source_plane_count > 0) // optinal! defaults are filled
885 3 ch = toupper(_source_planes_str[i]);
886
1/2
✓ Branch 198 → 199 taken 6 times.
✗ Branch 198 → 200 not taken.
6 else if (sourceIsYUV)
887 6 ch = toupper(yuv_source_planes_str_def[i]);
888 else // rgb
889 ch = toupper(rgb_source_planes_str_def[i]);
890
3/6
✓ Branch 201 → 202 taken 9 times.
✗ Branch 201 → 204 not taken.
✓ Branch 202 → 203 taken 9 times.
✗ Branch 202 → 204 not taken.
✗ Branch 203 → 204 not taken.
✓ Branch 203 → 205 taken 9 times.
9 bool isRGB = ch == 'R' || ch == 'G' || ch == 'B';
891
5/6
✓ Branch 206 → 207 taken 2 times.
✓ Branch 206 → 209 taken 7 times.
✓ Branch 207 → 208 taken 1 time.
✓ Branch 207 → 209 taken 1 time.
✓ Branch 208 → 209 taken 1 time.
✗ Branch 208 → 210 not taken.
9 bool isYUV = ch == 'Y' || ch == 'U' || ch == 'V';
892 9 bool isAlpha = ch == 'A';
893
2/6
✓ Branch 211 → 212 taken 9 times.
✗ Branch 211 → 215 not taken.
✗ Branch 212 → 213 not taken.
✓ Branch 212 → 215 taken 9 times.
✗ Branch 213 → 214 not taken.
✗ Branch 213 → 215 not taken.
9 if(!isRGB && !isYUV && !isAlpha)
894 env->ThrowError("CombinePlanes: invalid source plane definifion :%s", planes);
895
8/16
✓ Branch 215 → 216 taken 9 times.
✗ Branch 215 → 217 not taken.
✓ Branch 216 → 217 taken 9 times.
✗ Branch 216 → 223 not taken.
✗ Branch 217 → 218 not taken.
✓ Branch 217 → 219 taken 9 times.
✗ Branch 218 → 219 not taken.
✗ Branch 218 → 223 not taken.
✓ Branch 219 → 220 taken 9 times.
✗ Branch 219 → 221 not taken.
✓ Branch 220 → 221 taken 9 times.
✗ Branch 220 → 223 not taken.
✓ Branch 221 → 222 taken 6 times.
✓ Branch 221 → 224 taken 3 times.
✗ Branch 222 → 223 not taken.
✓ Branch 222 → 224 taken 6 times.
9 if((sourceIsYUV && isRGB) || (!sourceIsYUV && isYUV) || (!sourceHasAlpha && isAlpha) || (sourceIsY && ch!='Y'))
896 env->ThrowError("CombinePlanes: source has no such plane %c", ch);
897 // todo lambda
898 int current_source_plane;
899
3/8
✗ Branch 224 → 225 not taken.
✗ Branch 224 → 226 not taken.
✗ Branch 224 → 227 not taken.
✗ Branch 224 → 228 not taken.
✓ Branch 224 → 229 taken 7 times.
✓ Branch 224 → 230 taken 1 time.
✓ Branch 224 → 231 taken 1 time.
✗ Branch 224 → 232 not taken.
9 switch (ch) {
900 case 'R': current_source_plane = PLANAR_R; break;
901 case 'G': current_source_plane = PLANAR_G; break;
902 case 'B': current_source_plane = PLANAR_B; break;
903 case 'A': current_source_plane = PLANAR_A; break;
904 7 case 'Y': current_source_plane = PLANAR_Y; break;
905 1 case 'U': current_source_plane = PLANAR_U; break;
906 1 case 'V': current_source_plane = PLANAR_V; break;
907 }
908 9 source_planes[i] = current_source_plane;
909 // check dimensions
910
1/2
✓ Branch 232 → 233 taken 9 times.
✗ Branch 232 → 263 not taken.
9 int source_plane_width = src_vi.width >> src_vi.GetPlaneWidthSubsampling(current_source_plane);
911
1/2
✓ Branch 233 → 234 taken 9 times.
✗ Branch 233 → 263 not taken.
9 int source_plane_height = src_vi.height >> src_vi.GetPlaneHeightSubsampling(current_source_plane);
912
3/4
✓ Branch 234 → 235 taken 8 times.
✓ Branch 234 → 236 taken 1 time.
✗ Branch 235 → 236 not taken.
✓ Branch 235 → 237 taken 8 times.
9 if(source_plane_width != target_plane_width || source_plane_height != target_plane_height)
913
1/2
✗ Branch 236 → 237 not taken.
✓ Branch 236 → 263 taken 1 time.
1 env->ThrowError("CombinePlanes: source and target plane dimensions are different");
914 }
915 }
916
2/2
✓ Branch 267 → 268 taken 16 times.
✓ Branch 267 → 270 taken 4 times.
26 }
917
918
919 3 PVideoFrame __stdcall CombinePlanes::GetFrame(int n, IScriptEnvironment* env) {
920
921
1/2
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 254 not taken.
3 VideoInfo vi_src = clips[0]->GetVideoInfo();
922
923 // check if fast Subframe magic can replace BitBlt
924
7/10
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 10 taken 1 time.
✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 254 not taken.
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 254 not taken.
✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 10 not taken.
✓ Branch 11 → 12 taken 2 times.
✓ Branch 11 → 78 taken 1 time.
3 if (!clips[1] && vi.NumComponents() <= vi_src.NumComponents()) // YUV<->RGB, YUVA<->RGBA YUV->Y
925 {
926 // we have only one clip, plane shuffle is valid if target has less plane that defined in source
927
1/2
✓ Branch 13 → 14 taken 2 times.
✗ Branch 13 → 238 not taken.
2 PVideoFrame src = clips[0]->GetFrame(n, env);
928
929 2 int planes_y[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A };
930 2 int planes_r[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A };
931
2/8
✓ Branch 14 → 15 taken 2 times.
✗ Branch 14 → 236 not taken.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 18 taken 2 times.
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 236 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 19 not taken.
2 int *planes = (vi_src.IsYUV() || vi_src.IsYUVA()) ? planes_y : planes_r;
932
933 int Offsets[4];
934 int Pitches[4], NewPitches[4];
935 int RowSizes[4], NewRowSizes[4];
936
937 int RelOffsets[4];
938
939
3/4
✓ Branch 28 → 29 taken 8 times.
✗ Branch 28 → 236 not taken.
✓ Branch 29 → 21 taken 6 times.
✓ Branch 29 → 30 taken 2 times.
8 for (int i = 0; i < vi_src.NumComponents(); i++) {
940
1/2
✓ Branch 22 → 23 taken 6 times.
✗ Branch 22 → 236 not taken.
6 Offsets[i] = src->GetOffset(planes[i]);
941
1/2
✓ Branch 24 → 25 taken 6 times.
✗ Branch 24 → 236 not taken.
6 Pitches[i] = NewPitches[i] = src->GetPitch(planes[i]);
942
1/2
✓ Branch 26 → 27 taken 6 times.
✗ Branch 26 → 236 not taken.
6 RowSizes[i] = NewRowSizes[i] = src->GetRowSize(planes[i]);
943 6 RelOffsets[i] = 0;
944 }
945
946
2/2
✓ Branch 42 → 31 taken 6 times.
✓ Branch 42 → 43 taken 2 times.
8 for (int i = 0; i < planecount; i++) {
947 6 int target_plane = target_planes[i];
948 6 int source_plane = source_planes[i];
949 int target_index, source_index;
950
3/5
✓ Branch 31 → 32 taken 2 times.
✓ Branch 31 → 33 taken 2 times.
✓ Branch 31 → 34 taken 2 times.
✗ Branch 31 → 35 not taken.
✗ Branch 31 → 36 not taken.
6 switch (target_plane) {
951 2 case PLANAR_Y: case PLANAR_G: target_index = 0; break;
952 2 case PLANAR_U: case PLANAR_B: target_index = 1; break;
953 2 case PLANAR_V: case PLANAR_R: target_index = 2; break;
954 case PLANAR_A: target_index = 3; break;
955 }
956
3/5
✓ Branch 36 → 37 taken 2 times.
✓ Branch 36 → 38 taken 2 times.
✓ Branch 36 → 39 taken 2 times.
✗ Branch 36 → 40 not taken.
✗ Branch 36 → 41 not taken.
6 switch (source_plane) {
957 2 case PLANAR_Y: case PLANAR_G: source_index = 0; break;
958 2 case PLANAR_U: case PLANAR_B: source_index = 1; break;
959 2 case PLANAR_V: case PLANAR_R: source_index = 2; break;
960 case PLANAR_A: source_index = 3; break;
961 }
962 // !! if offsets would be size_t, be cautious when you subtract two unsigned size_t variables
963 6 RelOffsets[target_index] = Offsets[source_index] - Offsets[target_index];
964 6 NewPitches[target_index] = Pitches[source_index];
965 6 NewRowSizes[target_index] = RowSizes[source_index];
966 // Y U V A
967 // 10 1010 2010 3010 offsets
968 // src: AUVY target: YVUA
969 // 3010-10 2010-1010 1010-2010 10-3010
970 // 3000 =+1000 =-1000 =-3000 reloffsets
971 // 3010 2010 1010 10 new offsets inside
972 }
973
974
1/4
✓ Branch 43 → 44 taken 2 times.
✗ Branch 43 → 236 not taken.
✗ Branch 233 → 234 not taken.
✗ Branch 233 → 235 not taken.
2 PVideoFrame dst;
975
2/4
✓ Branch 44 → 45 taken 2 times.
✗ Branch 44 → 233 not taken.
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 54 taken 2 times.
2 if (vi.NumComponents() == 4) {
976 dst = env->SubframePlanarA(src, RelOffsets[0], NewPitches[0], NewRowSizes[0], src->GetHeight(),
977 RelOffsets[1], RelOffsets[2], NewPitches[1], RelOffsets[3]);
978 }
979
2/4
✓ Branch 54 → 55 taken 2 times.
✗ Branch 54 → 233 not taken.
✓ Branch 55 → 56 taken 2 times.
✗ Branch 55 → 64 not taken.
2 else if (vi.NumComponents() == 3) {
980
4/8
✓ Branch 57 → 58 taken 2 times.
✗ Branch 57 → 226 not taken.
✓ Branch 58 → 59 taken 2 times.
✗ Branch 58 → 225 not taken.
✓ Branch 59 → 60 taken 2 times.
✗ Branch 59 → 223 not taken.
✓ Branch 60 → 61 taken 2 times.
✗ Branch 60 → 221 not taken.
2 dst = env->SubframePlanar(src, RelOffsets[0], NewPitches[0], NewRowSizes[0], src->GetHeight(),
981 RelOffsets[1], RelOffsets[2], NewPitches[1]);
982 }
983 else {
984 dst = env->Subframe(src, RelOffsets[0], NewPitches[0], NewRowSizes[0], src->GetHeight());
985 }
986
987 // RGB(A)<->YUV(A) color space conversion can't be caught by Subframe...()
988
1/2
✓ Branch 73 → 74 taken 2 times.
✗ Branch 73 → 233 not taken.
2 dst->AmendPixelType(vi.pixel_type);
989
990
1/2
✗ Branch 74 → 75 not taken.
✓ Branch 74 → 76 taken 2 times.
2 return dst;
991 2 }
992
993 // check if first clip could be used as the target clip
994
1/2
✓ Branch 79 → 80 taken 1 time.
✗ Branch 79 → 254 not taken.
2 PVideoFrame src = clips[0]->GetFrame(n, env);
995
2/6
✓ Branch 81 → 82 taken 1 time.
✗ Branch 81 → 84 not taken.
✓ Branch 83 → 85 taken 1 time.
✗ Branch 83 → 252 not taken.
✗ Branch 84 → 85 not taken.
✗ Branch 84 → 252 not taken.
2 PVideoFrame src1 = clips[1] ? clips[1]->GetFrame(n, env) : nullptr;
996
997 // case 1: when Y is kept from the original clip and other planes may be merged
998
3/8
✓ Branch 85 → 86 taken 1 time.
✗ Branch 85 → 250 not taken.
✗ Branch 86 → 87 not taken.
✓ Branch 86 → 89 taken 1 time.
✗ Branch 87 → 88 not taken.
✗ Branch 87 → 89 not taken.
✗ Branch 90 → 91 not taken.
✓ Branch 90 → 132 taken 1 time.
1 if (vi_src.IsSameColorspace(vi) && target_planes[0] == source_planes[0]) {
999 // source (clip#0) has the same format as the target, and the first plane is the same
1000 // luma (Y) comes w/o BitBlt. Only U and V (and optionally A) is copied.
1001 if (src->IsWritable()) // we are the only one
1002 {
1003 src->AmendPixelType(vi.pixel_type);
1004
1005 PVideoFrame src_other = nullptr;
1006 bool writeptr_obtained = false;
1007
1008 for (int i = 1; i < planecount; i++) {
1009 int target_plane = target_planes[i];
1010 int source_plane = source_planes[i];
1011
1012 if (clips[i]) { // source clips can be less than defined planes
1013 if (!writeptr_obtained) {
1014 src->GetWritePtr(PLANAR_Y); //Must be requested BUT only if we actually do something
1015 writeptr_obtained = true;
1016 }
1017
1018 if (i == 1)
1019 src_other = src1; // already requested
1020 else
1021 src_other = clips[i]->GetFrame(n, env); // last defined clip is used for the others
1022 }
1023
1024 if (src_other) {
1025 env->BitBlt(src->GetWritePtr(target_plane), src->GetPitch(target_plane),
1026 src_other->GetReadPtr(source_plane), src_other->GetPitch(source_plane), src_other->GetRowSize(source_plane), src_other->GetHeight(source_plane));
1027 } else {
1028 // we are still at the first (master) clip, no need for plane copy
1029 }
1030 }
1031
1032 return src;
1033 }
1034 }
1035
3/6
✓ Branch 133 → 134 taken 1 time.
✗ Branch 133 → 137 not taken.
✗ Branch 135 → 136 not taken.
✓ Branch 135 → 137 taken 1 time.
✗ Branch 138 → 139 not taken.
✓ Branch 138 → 178 taken 1 time.
1 else if (clips[1] && !clips[2]){
1036 // Try to optimize a MergeLuma case, where luma comes from Y (can even be a format of single plane),
1037 // Clip a's UV is kept.
1038 // MergeLuma's speed gain: if 'a' is IsWritable() then there is no need for BitBlt chroma planes.
1039 // We can only make a BitBlt from Y.
1040 // We'd like to recognize the following scenario
1041 // Output YUV:
1042 // - Y from clip #0 (format:Y)
1043 // - UV from clip #1 (format YUV420, same as output)
1044 // planes: "YUV"
1045 //
1046 // clip #0 format does not match with the output, maybe it is a single plane
1047 // let's try with the second (clip #1) if it can be used
1048 if (clips[1]->GetVideoInfo().IsSameColorspace(vi) &&
1049 // the rest plane IDs are matching between source and target
1050 vi.NumComponents() >= 3 && target_planes[1] == source_planes[1] && target_planes[2] == source_planes[2] &&
1051 (vi.NumComponents() < 4 || (vi.NumComponents() == 4 && target_planes[3] == source_planes[3])))
1052 {
1053 if (src1->IsWritable()) // we are the only one
1054 {
1055 src1->AmendPixelType(vi.pixel_type);
1056
1057 src1->GetWritePtr(PLANAR_Y); //Must be requested BUT only if we actually do something
1058
1059 int target_plane = target_planes[0];
1060 int source_plane = source_planes[0];
1061
1062 // Copy from first clip
1063 env->BitBlt(src1->GetWritePtr(target_plane), src1->GetPitch(target_plane),
1064 src->GetReadPtr(source_plane), src->GetPitch(source_plane), src->GetRowSize(source_plane), src->GetHeight(source_plane));
1065
1066 env->copyFrameProps(src, src1);
1067
1068 return src1;
1069 }
1070 }
1071 }
1072
1073
1/2
✓ Branch 178 → 179 taken 1 time.
✗ Branch 178 → 250 not taken.
2 PVideoFrame dst = env->NewVideoFrame(vi);
1074 1 bool propCopied = false;
1075
1076
2/2
✓ Branch 207 → 180 taken 3 times.
✓ Branch 207 → 208 taken 1 time.
4 for (int i = 0; i < planecount; i++) {
1077
1/2
✓ Branch 181 → 182 taken 3 times.
✗ Branch 181 → 193 not taken.
3 if (clips[i]) { // source clips can be less than defined planes
1078
2/2
✓ Branch 182 → 183 taken 2 times.
✓ Branch 182 → 190 taken 1 time.
3 if (i > 0) { // clip #0 was already requested
1079
2/2
✓ Branch 183 → 184 taken 1 time.
✓ Branch 183 → 185 taken 1 time.
2 if (i == 1) // clip #1 was already requested
1080
1/2
✓ Branch 184 → 190 taken 1 time.
✗ Branch 184 → 248 not taken.
1 src = src1;
1081 else
1082
2/4
✓ Branch 186 → 187 taken 1 time.
✗ Branch 186 → 247 not taken.
✓ Branch 187 → 188 taken 1 time.
✗ Branch 187 → 245 not taken.
1 src = clips[i]->GetFrame(n, env); // last defined clip is used for the others
1083 }
1084
1085
2/2
✓ Branch 190 → 191 taken 1 time.
✓ Branch 190 → 193 taken 2 times.
3 if (!propCopied) {
1086
1/2
✓ Branch 191 → 192 taken 1 time.
✗ Branch 191 → 248 not taken.
1 env->copyFrameProps(src, dst);
1087 1 propCopied = true;
1088 }
1089 }
1090
1091 3 int target_plane = target_planes[i];
1092 3 int source_plane = source_planes[i];
1093
1094
7/14
✓ Branch 194 → 195 taken 3 times.
✗ Branch 194 → 248 not taken.
✓ Branch 196 → 197 taken 3 times.
✗ Branch 196 → 248 not taken.
✓ Branch 198 → 199 taken 3 times.
✗ Branch 198 → 248 not taken.
✓ Branch 200 → 201 taken 3 times.
✗ Branch 200 → 248 not taken.
✓ Branch 202 → 203 taken 3 times.
✗ Branch 202 → 248 not taken.
✓ Branch 204 → 205 taken 3 times.
✗ Branch 204 → 248 not taken.
✓ Branch 205 → 206 taken 3 times.
✗ Branch 205 → 248 not taken.
3 env->BitBlt(dst->GetWritePtr(target_plane), dst->GetPitch(target_plane),
1095 src->GetReadPtr(source_plane), src->GetPitch(source_plane), src->GetRowSize(source_plane), src->GetHeight(source_plane));
1096 }
1097
1098
1/2
✓ Branch 208 → 209 taken 1 time.
✗ Branch 208 → 248 not taken.
1 return dst;
1099 }
1100