GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 45.5% 332 / 0 / 730
Functions: 56.0% 14 / 0 / 25
Branches: 26.4% 367 / 0 / 1388

filters/transform.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 #include "transform.h"
36 #include "../convert/convert_matrix.h"
37 #include "../convert/convert_helper.h"
38 #include <avs/minmax.h>
39 #include "../core/bitblt.h"
40 #include <stdint.h>
41 #include "resample_functions.h"
42 #include "../convert/convert_planar.h"
43 #include "combine.h"
44 #include <vector>
45 #include <cmath>
46
47
48
49 /********************************************************************
50 ***** Declare index of new filters for Avisynth's filter engine *****
51 ********************************************************************/
52
53 extern const AVSFunction Transform_filters[] = {
54 { "FlipVertical", BUILTIN_FUNC_PREFIX, "c", FlipVertical::Create },
55 { "FlipHorizontal", BUILTIN_FUNC_PREFIX, "c", FlipHorizontal::Create },
56 { "Crop", BUILTIN_FUNC_PREFIX, "ciiii[align]b", Crop::Create }, // left, top, width, height *OR*
57 // left, top, -right, -bottom (VDub style)
58 { "CropBottom", BUILTIN_FUNC_PREFIX, "ci", Create_CropBottom }, // bottom amount
59 { "AddBorders", BUILTIN_FUNC_PREFIX, "ciiii[color]i[color_yuv]i[resample]s[param1]f[param2]f[param3]f[r]i", AddBorders::Create }, // left, top, right, bottom [,color] [,color_yuv]
60 { "Letterbox", BUILTIN_FUNC_PREFIX, "cii[x1]i[x2]i[color]i[color_yuv]i[resample]s[param1]f[param2]f[param3]f[r]i", Create_Letterbox }, // top, bottom, [left], [right] [,color] [,color_yuv]
61 { 0 }
62 };
63
64
65
66
67
68 /********************************
69 ******* Flip Vertical ******
70 ********************************/
71
72 5 PVideoFrame FlipVertical::GetFrame(int n, IScriptEnvironment* env) {
73
1/2
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 84 not taken.
5 PVideoFrame src = child->GetFrame(n, env);
74
1/2
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 82 not taken.
5 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
75
1/2
✓ Branch 6 → 7 taken 5 times.
✗ Branch 6 → 80 not taken.
5 const BYTE* srcp = src->GetReadPtr();
76
1/2
✓ Branch 8 → 9 taken 5 times.
✗ Branch 8 → 80 not taken.
5 BYTE* dstp = dst->GetWritePtr();
77
1/2
✓ Branch 10 → 11 taken 5 times.
✗ Branch 10 → 80 not taken.
5 int row_size = src->GetRowSize();
78
1/2
✓ Branch 12 → 13 taken 5 times.
✗ Branch 12 → 80 not taken.
5 int src_pitch = src->GetPitch();
79
1/2
✓ Branch 14 → 15 taken 5 times.
✗ Branch 14 → 80 not taken.
5 int dst_pitch = dst->GetPitch();
80
1/2
✓ Branch 15 → 16 taken 5 times.
✗ Branch 15 → 80 not taken.
5 env->BitBlt(dstp, dst_pitch, srcp + (vi.height-1) * src_pitch, -src_pitch, row_size, vi.height);
81
82
4/8
✓ Branch 16 → 17 taken 5 times.
✗ Branch 16 → 80 not taken.
✓ Branch 17 → 18 taken 5 times.
✗ Branch 17 → 20 not taken.
✓ Branch 18 → 19 taken 5 times.
✗ Branch 18 → 80 not taken.
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 5 times.
5 bool isRGBPfamily = vi.IsPlanarRGB() || vi.IsPlanarRGBA();
83
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 5 times.
5 int planeUB = isRGBPfamily ? PLANAR_B : PLANAR_U;
84
1/2
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 5 times.
5 int planeVR = isRGBPfamily ? PLANAR_R : PLANAR_V;
85
86
3/4
✓ Branch 29 → 30 taken 5 times.
✗ Branch 29 → 80 not taken.
✓ Branch 30 → 31 taken 3 times.
✓ Branch 30 → 77 taken 2 times.
5 if (src->GetPitch(planeUB)) {
87
1/2
✓ Branch 32 → 33 taken 3 times.
✗ Branch 32 → 80 not taken.
3 srcp = src->GetReadPtr(planeUB);
88
1/2
✓ Branch 34 → 35 taken 3 times.
✗ Branch 34 → 80 not taken.
3 dstp = dst->GetWritePtr(planeUB);
89
1/2
✓ Branch 36 → 37 taken 3 times.
✗ Branch 36 → 80 not taken.
3 row_size = src->GetRowSize(planeUB);
90
1/2
✓ Branch 38 → 39 taken 3 times.
✗ Branch 38 → 80 not taken.
3 src_pitch = src->GetPitch(planeUB);
91
1/2
✓ Branch 40 → 41 taken 3 times.
✗ Branch 40 → 80 not taken.
3 dst_pitch = dst->GetPitch(planeUB);
92
3/6
✓ Branch 42 → 43 taken 3 times.
✗ Branch 42 → 80 not taken.
✓ Branch 44 → 45 taken 3 times.
✗ Branch 44 → 80 not taken.
✓ Branch 45 → 46 taken 3 times.
✗ Branch 45 → 80 not taken.
3 env->BitBlt(dstp, dst_pitch, srcp + (src->GetHeight(planeUB)-1) * src_pitch, -src_pitch, row_size, src->GetHeight(planeUB));
93
94
1/2
✓ Branch 47 → 48 taken 3 times.
✗ Branch 47 → 80 not taken.
3 srcp = src->GetReadPtr(planeVR);
95
1/2
✓ Branch 49 → 50 taken 3 times.
✗ Branch 49 → 80 not taken.
3 dstp = dst->GetWritePtr(planeVR);
96
3/6
✓ Branch 51 → 52 taken 3 times.
✗ Branch 51 → 80 not taken.
✓ Branch 53 → 54 taken 3 times.
✗ Branch 53 → 80 not taken.
✓ Branch 54 → 55 taken 3 times.
✗ Branch 54 → 80 not taken.
3 env->BitBlt(dstp, dst_pitch, srcp + (src->GetHeight(planeVR)-1) * src_pitch, -src_pitch, row_size, src->GetHeight(planeVR));
97
98
7/10
✓ Branch 55 → 56 taken 3 times.
✗ Branch 55 → 80 not taken.
✓ Branch 56 → 57 taken 2 times.
✓ Branch 56 → 59 taken 1 time.
✓ Branch 57 → 58 taken 2 times.
✗ Branch 57 → 80 not taken.
✗ Branch 58 → 59 not taken.
✓ Branch 58 → 60 taken 2 times.
✓ Branch 61 → 62 taken 1 time.
✓ Branch 61 → 77 taken 2 times.
3 if (vi.IsYUVA() || vi.IsPlanarRGBA())
99 {
100
1/2
✓ Branch 63 → 64 taken 1 time.
✗ Branch 63 → 80 not taken.
1 srcp = src->GetReadPtr(PLANAR_A);
101
1/2
✓ Branch 65 → 66 taken 1 time.
✗ Branch 65 → 80 not taken.
1 dstp = dst->GetWritePtr(PLANAR_A);
102
1/2
✓ Branch 67 → 68 taken 1 time.
✗ Branch 67 → 80 not taken.
1 row_size = src->GetRowSize(PLANAR_A);
103
1/2
✓ Branch 69 → 70 taken 1 time.
✗ Branch 69 → 80 not taken.
1 src_pitch = src->GetPitch(PLANAR_A);
104
1/2
✓ Branch 71 → 72 taken 1 time.
✗ Branch 71 → 80 not taken.
1 dst_pitch = dst->GetPitch(PLANAR_A);
105
3/6
✓ Branch 73 → 74 taken 1 time.
✗ Branch 73 → 80 not taken.
✓ Branch 75 → 76 taken 1 time.
✗ Branch 75 → 80 not taken.
✓ Branch 76 → 77 taken 1 time.
✗ Branch 76 → 80 not taken.
1 env->BitBlt(dstp, dst_pitch, srcp + (src->GetHeight(PLANAR_A)-1) * src_pitch, -src_pitch, row_size, src->GetHeight(PLANAR_A));
106 }
107 }
108 5 return dst;
109 5 }
110
111 AVSValue __cdecl FlipVertical::Create(AVSValue args, void*, IScriptEnvironment* env)
112 {
113 AVS_UNUSED(env);
114 return new FlipVertical(args[0].AsClip());
115 }
116
117
118
119 /********************************
120 ******* Flip Horizontal ******
121 ********************************/
122
123 template<typename pixel_t>
124 18 static void flip_horizontal_plane_c(BYTE* dstp, const BYTE* srcp, int dst_pitch, int src_pitch, int width, int height) {
125 18 width = width / sizeof(pixel_t); // width is called with GetRowSize value
126 18 dstp += (width - 1) * sizeof(pixel_t);
127
6/10
void flip_horizontal_plane_c<float>(unsigned char*, unsigned char const*, int, int, int, int):
✗ Branch 7 → 3 not taken.
✗ Branch 7 → 8 not taken.
void flip_horizontal_plane_c<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 7 → 3 taken 57 times.
✓ Branch 7 → 8 taken 14 times.
void flip_horizontal_plane_c<unsigned int>(unsigned char*, unsigned char const*, int, int, int, int):
✗ Branch 7 → 3 not taken.
✗ Branch 7 → 8 not taken.
void flip_horizontal_plane_c<unsigned long>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 7 → 3 taken 4 times.
✓ Branch 7 → 8 taken 1 time.
void flip_horizontal_plane_c<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 7 → 3 taken 12 times.
✓ Branch 7 → 8 taken 3 times.
91 for (int y = 0; y < height; y++) { // Loop planar luma.
128
6/10
void flip_horizontal_plane_c<float>(unsigned char*, unsigned char const*, int, int, int, int):
✗ Branch 5 → 4 not taken.
✗ Branch 5 → 6 not taken.
void flip_horizontal_plane_c<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 5 → 4 taken 357 times.
✓ Branch 5 → 6 taken 57 times.
void flip_horizontal_plane_c<unsigned int>(unsigned char*, unsigned char const*, int, int, int, int):
✗ Branch 5 → 4 not taken.
✗ Branch 5 → 6 not taken.
void flip_horizontal_plane_c<unsigned long>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 5 → 4 taken 20 times.
✓ Branch 5 → 6 taken 4 times.
void flip_horizontal_plane_c<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int):
✓ Branch 5 → 4 taken 84 times.
✓ Branch 5 → 6 taken 12 times.
534 for (int x = 0; x < width; x++) {
129 461 (reinterpret_cast<pixel_t *>(dstp))[-x] = (reinterpret_cast<const pixel_t *>(srcp))[x];
130 }
131 73 srcp += src_pitch;
132 73 dstp += dst_pitch;
133 }
134 18 }
135
136 7 PVideoFrame FlipHorizontal::GetFrame(int n, IScriptEnvironment* env) {
137
1/2
✓ Branch 3 → 4 taken 7 times.
✗ Branch 3 → 118 not taken.
7 PVideoFrame src = child->GetFrame(n, env);
138
1/2
✓ Branch 4 → 5 taken 7 times.
✗ Branch 4 → 116 not taken.
7 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
139
1/2
✓ Branch 6 → 7 taken 7 times.
✗ Branch 6 → 114 not taken.
7 const BYTE* srcp = src->GetReadPtr();
140
1/2
✓ Branch 8 → 9 taken 7 times.
✗ Branch 8 → 114 not taken.
7 BYTE* dstp = dst->GetWritePtr();
141
1/2
✓ Branch 10 → 11 taken 7 times.
✗ Branch 10 → 114 not taken.
7 int width = src->GetRowSize();
142
1/2
✓ Branch 12 → 13 taken 7 times.
✗ Branch 12 → 114 not taken.
7 int src_pitch = src->GetPitch();
143
1/2
✓ Branch 14 → 15 taken 7 times.
✗ Branch 14 → 114 not taken.
7 int dst_pitch = dst->GetPitch();
144
1/2
✓ Branch 16 → 17 taken 7 times.
✗ Branch 16 → 114 not taken.
7 int height = src->GetHeight();
145
2/4
✓ Branch 17 → 18 taken 7 times.
✗ Branch 17 → 114 not taken.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 26 taken 7 times.
7 if (vi.IsYUY2()) { // Avoid flipping UV in YUY2 mode.
146 srcp += width;
147 srcp -= 4;
148 for (int y = 0; y<height; y++) {
149 for (int x = 0; x<width; x += 4) {
150 dstp[x] = srcp[-x+2];
151 dstp[x+1] = srcp[-x+1];
152 dstp[x+2] = srcp[-x];
153 dstp[x+3] = srcp[-x+3];
154 }
155 srcp += src_pitch;
156 dstp += dst_pitch;
157 }
158 return dst;
159 }
160
161 typedef void(*FlipFuncPtr) (BYTE * dstp, const BYTE * srcp, int dst_pitch, int src_pitch, int width, int height);
162 FlipFuncPtr flip_h_func;
163
164
3/4
✓ Branch 26 → 27 taken 7 times.
✗ Branch 26 → 114 not taken.
✓ Branch 27 → 28 taken 5 times.
✓ Branch 27 → 88 taken 2 times.
7 if (vi.IsPlanar()) {
165
3/5
✓ Branch 28 → 29 taken 5 times.
✗ Branch 28 → 114 not taken.
✓ Branch 29 → 30 taken 4 times.
✓ Branch 29 → 31 taken 1 time.
✗ Branch 29 → 32 not taken.
5 switch (vi.ComponentSize()) // AVS16
166 {
167 4 case 1: flip_h_func = flip_horizontal_plane_c<uint8_t>; break;
168 1 case 2: flip_h_func = flip_horizontal_plane_c<uint16_t>; break;
169 default: // 4 float
170 flip_h_func = flip_horizontal_plane_c<float>; break;
171 }
172
1/2
✓ Branch 33 → 34 taken 5 times.
✗ Branch 33 → 114 not taken.
5 flip_h_func(dstp, srcp, dst_pitch, src_pitch, width, height);
173
174
5/8
✓ Branch 34 → 35 taken 5 times.
✗ Branch 34 → 114 not taken.
✓ Branch 35 → 36 taken 4 times.
✓ Branch 35 → 38 taken 1 time.
✓ Branch 36 → 37 taken 4 times.
✗ Branch 36 → 114 not taken.
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 4 times.
5 bool isRGBPfamily = vi.IsPlanarRGB() || vi.IsPlanarRGBA();
175
2/2
✓ Branch 40 → 41 taken 1 time.
✓ Branch 40 → 42 taken 4 times.
5 int planeUB = isRGBPfamily ? PLANAR_B : PLANAR_U;
176
2/2
✓ Branch 43 → 44 taken 1 time.
✓ Branch 43 → 45 taken 4 times.
5 int planeVR = isRGBPfamily ? PLANAR_R : PLANAR_V;
177
178
2/4
✓ Branch 47 → 48 taken 5 times.
✗ Branch 47 → 114 not taken.
✓ Branch 48 → 49 taken 5 times.
✗ Branch 48 → 87 not taken.
5 if (src->GetPitch(planeUB)) {
179
1/2
✓ Branch 50 → 51 taken 5 times.
✗ Branch 50 → 114 not taken.
5 srcp = src->GetReadPtr(planeUB);
180
1/2
✓ Branch 52 → 53 taken 5 times.
✗ Branch 52 → 114 not taken.
5 dstp = dst->GetWritePtr(planeUB);
181
1/2
✓ Branch 54 → 55 taken 5 times.
✗ Branch 54 → 114 not taken.
5 width = src->GetRowSize(planeUB);
182
1/2
✓ Branch 56 → 57 taken 5 times.
✗ Branch 56 → 114 not taken.
5 src_pitch = src->GetPitch(planeUB);
183
1/2
✓ Branch 58 → 59 taken 5 times.
✗ Branch 58 → 114 not taken.
5 dst_pitch = dst->GetPitch(planeUB);
184
1/2
✓ Branch 60 → 61 taken 5 times.
✗ Branch 60 → 114 not taken.
5 height = src->GetHeight(planeUB);
185
1/2
✓ Branch 61 → 62 taken 5 times.
✗ Branch 61 → 114 not taken.
5 flip_h_func(dstp, srcp, dst_pitch, src_pitch, width, height);
186
187
1/2
✓ Branch 63 → 64 taken 5 times.
✗ Branch 63 → 114 not taken.
5 srcp = src->GetReadPtr(planeVR);
188
1/2
✓ Branch 65 → 66 taken 5 times.
✗ Branch 65 → 114 not taken.
5 dstp = dst->GetWritePtr(planeVR);
189
190
1/2
✓ Branch 66 → 67 taken 5 times.
✗ Branch 66 → 114 not taken.
5 flip_h_func(dstp, srcp, dst_pitch, src_pitch, width, height);
191
192
7/10
✓ Branch 67 → 68 taken 5 times.
✗ Branch 67 → 114 not taken.
✓ Branch 68 → 69 taken 3 times.
✓ Branch 68 → 71 taken 2 times.
✓ Branch 69 → 70 taken 3 times.
✗ Branch 69 → 114 not taken.
✗ Branch 70 → 71 not taken.
✓ Branch 70 → 72 taken 3 times.
✓ Branch 73 → 74 taken 2 times.
✓ Branch 73 → 87 taken 3 times.
5 if (vi.IsYUVA() || vi.IsPlanarRGBA())
193 {
194
1/2
✓ Branch 75 → 76 taken 2 times.
✗ Branch 75 → 114 not taken.
2 srcp = src->GetReadPtr(PLANAR_A);
195
1/2
✓ Branch 77 → 78 taken 2 times.
✗ Branch 77 → 114 not taken.
2 dstp = dst->GetWritePtr(PLANAR_A);
196
1/2
✓ Branch 79 → 80 taken 2 times.
✗ Branch 79 → 114 not taken.
2 width = src->GetRowSize(PLANAR_A);
197
1/2
✓ Branch 81 → 82 taken 2 times.
✗ Branch 81 → 114 not taken.
2 src_pitch = src->GetPitch(PLANAR_A);
198
1/2
✓ Branch 83 → 84 taken 2 times.
✗ Branch 83 → 114 not taken.
2 dst_pitch = dst->GetPitch(PLANAR_A);
199
1/2
✓ Branch 85 → 86 taken 2 times.
✗ Branch 85 → 114 not taken.
2 height = src->GetHeight(PLANAR_A);
200
1/2
✓ Branch 86 → 87 taken 2 times.
✗ Branch 86 → 114 not taken.
2 flip_h_func(dstp, srcp, dst_pitch, src_pitch, width, height);
201 }
202 }
203 5 return dst;
204 }
205
206 // width is GetRowSize
207
2/4
✓ Branch 88 → 89 taken 2 times.
✗ Branch 88 → 114 not taken.
✗ Branch 89 → 90 not taken.
✓ Branch 89 → 91 taken 2 times.
2 if (vi.IsRGB32()) { // fast method
208 flip_h_func = flip_horizontal_plane_c<uint32_t>;
209 flip_h_func(dstp, srcp, dst_pitch, src_pitch, width, height);
210 }
211
3/4
✓ Branch 91 → 92 taken 2 times.
✗ Branch 91 → 114 not taken.
✓ Branch 92 → 93 taken 1 time.
✓ Branch 92 → 94 taken 1 time.
2 else if (vi.IsRGB64()) {
212 1 flip_h_func = flip_horizontal_plane_c<uint64_t>;
213
1/2
✓ Branch 93 → 110 taken 1 time.
✗ Branch 93 → 114 not taken.
1 flip_h_func(dstp, srcp, dst_pitch, src_pitch, width, height);
214 }
215
2/4
✓ Branch 94 → 95 taken 1 time.
✗ Branch 94 → 114 not taken.
✓ Branch 95 → 96 taken 1 time.
✗ Branch 95 → 102 not taken.
1 else if (vi.IsRGB24()) {
216 1 dstp += width - 3;
217
2/2
✓ Branch 101 → 97 taken 4 times.
✓ Branch 101 → 110 taken 1 time.
5 for (int y = 0; y < height; y++) {
218
2/2
✓ Branch 99 → 98 taken 20 times.
✓ Branch 99 → 100 taken 4 times.
24 for (int x = 0; x < width; x += 3) {
219 20 dstp[-x + 0] = srcp[x + 0];
220 20 dstp[-x + 1] = srcp[x + 1];
221 20 dstp[-x + 2] = srcp[x + 2];
222 }
223 4 srcp += src_pitch;
224 4 dstp += dst_pitch;
225 }
226 }
227 else if (vi.IsRGB48()) {
228 dstp += width - 3 * sizeof(uint16_t);
229 for (int y = 0; y < height; y++) {
230 for (int x = 0; x < width / 2 /*sizeof(uint16_t)*/; x += 3) {
231 reinterpret_cast<uint16_t*>(dstp)[-x + 0] = reinterpret_cast<const uint16_t*>(srcp)[x + 0];
232 reinterpret_cast<uint16_t*>(dstp)[-x + 1] = reinterpret_cast<const uint16_t*>(srcp)[x + 1];
233 reinterpret_cast<uint16_t*>(dstp)[-x + 2] = reinterpret_cast<const uint16_t*>(srcp)[x + 2];
234 }
235 srcp += src_pitch;
236 dstp += dst_pitch;
237 }
238 }
239 2 return dst;
240 7 }
241
242
243 AVSValue __cdecl FlipHorizontal::Create(AVSValue args, void*, IScriptEnvironment* env)
244 {
245 AVS_UNUSED(env);
246 return new FlipHorizontal(args[0].AsClip());
247 }
248
249
250
251
252
253 /******************************
254 ******* Crop Filter ******
255 *****************************/
256
257 6 Crop::Crop(int _left, int _top, int _width, int _height, bool _align, PClip _child, IScriptEnvironment* env)
258
2/4
✓ Branch 2 → 3 taken 6 times.
✗ Branch 2 → 57 not taken.
✓ Branch 3 → 4 taken 6 times.
✗ Branch 3 → 55 not taken.
6 : GenericVideoFilter(_child), align(FRAME_ALIGN - 1), xsub(0), ysub(0)
259 {
260 AVS_UNUSED(_align);
261 // _align parameter exists only for the backward compatibility.
262
263 /* Negative values -> VDub-style syntax
264 Namely, Crop(a, b, -c, -d) will crop c pixels from the right and d pixels from the bottom.
265 Flags on 0 values too since AFAICT it's much more useful to this syntax than the standard one. */
266
2/4
✓ Branch 5 → 6 taken 6 times.
✗ Branch 5 → 7 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 6 times.
6 if ( (_left<0) || (_top<0) )
267 env->ThrowError("Crop: Top and Left must be more than 0");
268
269
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 6 times.
6 if (_width <= 0)
270 _width = vi.width - _left + _width;
271
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 6 times.
6 if (_height <= 0)
272 _height = vi.height - _top + _height;
273
274
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 6 times.
6 if (_width <=0)
275 env->ThrowError("Crop: Destination width is 0 or less.");
276
277
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 6 times.
6 if (_height<=0)
278 env->ThrowError("Crop: Destination height is 0 or less.");
279
280
2/4
✓ Branch 16 → 17 taken 6 times.
✗ Branch 16 → 18 not taken.
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 6 times.
6 if (_left + _width > vi.width || _top + _height > vi.height)
281 env->ThrowError("Crop: you cannot use crop to enlarge or 'shift' a clip");
282
283
5/8
✓ Branch 19 → 20 taken 6 times.
✗ Branch 19 → 58 not taken.
✓ Branch 20 → 21 taken 5 times.
✓ Branch 20 → 23 taken 1 time.
✓ Branch 21 → 22 taken 5 times.
✗ Branch 21 → 58 not taken.
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 5 times.
6 isRGBPfamily = vi.IsPlanarRGB() || vi.IsPlanarRGBA();
284
5/8
✓ Branch 25 → 26 taken 6 times.
✗ Branch 25 → 58 not taken.
✓ Branch 26 → 27 taken 6 times.
✗ Branch 26 → 29 not taken.
✓ Branch 27 → 28 taken 6 times.
✗ Branch 27 → 58 not taken.
✓ Branch 28 → 29 taken 1 time.
✓ Branch 28 → 30 taken 5 times.
6 hasAlpha = vi.IsPlanarRGBA() || vi.IsYUVA();
285
286
8/10
✓ Branch 31 → 32 taken 6 times.
✗ Branch 31 → 58 not taken.
✓ Branch 32 → 33 taken 3 times.
✓ Branch 32 → 35 taken 3 times.
✓ Branch 33 → 34 taken 3 times.
✗ Branch 33 → 58 not taken.
✓ Branch 34 → 35 taken 1 time.
✓ Branch 34 → 36 taken 2 times.
✓ Branch 37 → 38 taken 4 times.
✓ Branch 37 → 51 taken 2 times.
6 if (vi.IsYUV() || vi.IsYUVA()) {
287
2/4
✓ Branch 38 → 39 taken 4 times.
✗ Branch 38 → 58 not taken.
✓ Branch 39 → 40 taken 4 times.
✗ Branch 39 → 43 not taken.
4 if (vi.NumComponents() > 1) {
288
1/2
✓ Branch 40 → 41 taken 4 times.
✗ Branch 40 → 58 not taken.
4 xsub=vi.GetPlaneWidthSubsampling(PLANAR_U);
289
1/2
✓ Branch 41 → 42 taken 4 times.
✗ Branch 41 → 58 not taken.
4 ysub=vi.GetPlaneHeightSubsampling(PLANAR_U);
290 }
291 4 const int xmask = (1 << xsub) - 1;
292 4 const int ymask = (1 << ysub) - 1;
293
294 // YUY2, etc, ... can only crop to even pixel boundaries horizontally
295
1/2
✗ Branch 43 → 44 not taken.
✓ Branch 43 → 45 taken 4 times.
4 if (_left & xmask)
296 env->ThrowError("Crop: YUV image can only be cropped by Mod %d (left side).", xmask+1);
297
1/2
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 4 times.
4 if (_width & xmask)
298 env->ThrowError("Crop: YUV image can only be cropped by Mod %d (right side).", xmask+1);
299
1/2
✗ Branch 47 → 48 not taken.
✓ Branch 47 → 49 taken 4 times.
4 if (_top & ymask)
300 env->ThrowError("Crop: YUV image can only be cropped by Mod %d (top).", ymask+1);
301
1/2
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 53 taken 4 times.
4 if (_height & ymask)
302 env->ThrowError("Crop: YUV image can only be cropped by Mod %d (bottom).", ymask+1);
303
2/2
✓ Branch 51 → 52 taken 1 time.
✓ Branch 51 → 53 taken 1 time.
2 } else if (!isRGBPfamily) {
304 // RGB is upside-down
305 1 _top = vi.height - _height - _top;
306 }
307
308
1/2
✓ Branch 53 → 54 taken 6 times.
✗ Branch 53 → 58 not taken.
6 left_bytes = vi.BytesFromPixels(_left);
309 6 top = _top;
310 6 vi.width = _width;
311 6 vi.height = _height;
312
313 6 }
314
315
316 6 PVideoFrame Crop::GetFrame(int n, IScriptEnvironment* env_)
317 {
318
1/2
✓ Branch 2 → 3 taken 6 times.
✗ Branch 2 → 162 not taken.
6 InternalEnvironment* IEnv = GetAndRevealCamouflagedEnv(env_); // though here a static cast would do
319 6 IScriptEnvironment* env = static_cast<IScriptEnvironment*>(IEnv);
320
321
1/2
✓ Branch 4 → 5 taken 6 times.
✗ Branch 4 → 162 not taken.
6 PVideoFrame frame = child->GetFrame(n, env);
322
323
2/2
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 5 times.
6 int plane0 = isRGBPfamily ? PLANAR_G : PLANAR_Y;
324
2/2
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 5 times.
6 int plane1 = isRGBPfamily ? PLANAR_B : PLANAR_U;
325
2/2
✓ Branch 11 → 12 taken 1 time.
✓ Branch 11 → 13 taken 5 times.
6 int plane2 = isRGBPfamily ? PLANAR_R : PLANAR_V;
326
327
2/4
✓ Branch 15 → 16 taken 6 times.
✗ Branch 15 → 160 not taken.
✓ Branch 17 → 18 taken 6 times.
✗ Branch 17 → 160 not taken.
6 const BYTE* srcp0 = frame->GetReadPtr(plane0) + top * frame->GetPitch(plane0) + left_bytes;
328
2/4
✓ Branch 19 → 20 taken 6 times.
✗ Branch 19 → 160 not taken.
✓ Branch 21 → 22 taken 6 times.
✗ Branch 21 → 160 not taken.
6 const BYTE* srcp1 = frame->GetReadPtr(plane1) + (top>>ysub) * frame->GetPitch(plane1) + (left_bytes>>xsub);
329
2/4
✓ Branch 23 → 24 taken 6 times.
✗ Branch 23 → 160 not taken.
✓ Branch 25 → 26 taken 6 times.
✗ Branch 25 → 160 not taken.
6 const BYTE* srcp2 = frame->GetReadPtr(plane2) + (top>>ysub) * frame->GetPitch(plane2) + (left_bytes>>xsub);
330
331 size_t _align;
332
333
10/14
✓ Branch 27 → 28 taken 6 times.
✗ Branch 27 → 160 not taken.
✓ Branch 28 → 29 taken 5 times.
✓ Branch 28 → 34 taken 1 time.
✓ Branch 29 → 30 taken 5 times.
✗ Branch 29 → 160 not taken.
✓ Branch 30 → 31 taken 1 time.
✓ Branch 30 → 33 taken 4 times.
✓ Branch 31 → 32 taken 1 time.
✗ Branch 31 → 160 not taken.
✓ Branch 32 → 33 taken 1 time.
✗ Branch 32 → 34 not taken.
✓ Branch 35 → 36 taken 5 times.
✓ Branch 35 → 37 taken 1 time.
6 if (frame->GetPitch(plane1) && (!vi.IsYV12() || env->PlanarChromaAlignment(IScriptEnvironment::PlanarChromaAlignmentTest)))
334 5 _align = this->align & ((size_t)srcp0|(size_t)srcp1|(size_t)srcp2);
335 else
336 1 _align = this->align & (size_t)srcp0;
337
338 // Ignore alignment for CUDA. Clip should be explicitly aligned by Align()
339
4/8
✓ Branch 38 → 39 taken 6 times.
✗ Branch 38 → 42 not taken.
✓ Branch 39 → 40 taken 6 times.
✗ Branch 39 → 160 not taken.
✓ Branch 40 → 41 taken 6 times.
✗ Branch 40 → 42 not taken.
✓ Branch 43 → 44 taken 6 times.
✗ Branch 43 → 97 not taken.
6 if (0 != _align && (IEnv->GetDeviceType() == DEV_TYPE_CPU)) {
340
1/4
✓ Branch 44 → 45 taken 6 times.
✗ Branch 44 → 160 not taken.
✗ Branch 148 → 149 not taken.
✗ Branch 148 → 150 not taken.
6 PVideoFrame dst = env->NewVideoFrameP(vi, &frame, (int)align+1);
341
342
6/12
✓ Branch 46 → 47 taken 6 times.
✗ Branch 46 → 148 not taken.
✓ Branch 48 → 49 taken 6 times.
✗ Branch 48 → 148 not taken.
✓ Branch 50 → 51 taken 6 times.
✗ Branch 50 → 148 not taken.
✓ Branch 52 → 53 taken 6 times.
✗ Branch 52 → 148 not taken.
✓ Branch 54 → 55 taken 6 times.
✗ Branch 54 → 148 not taken.
✓ Branch 55 → 56 taken 6 times.
✗ Branch 55 → 148 not taken.
6 env->BitBlt(dst->GetWritePtr(plane0), dst->GetPitch(plane0), srcp0,
343 frame->GetPitch(plane0), dst->GetRowSize(plane0), dst->GetHeight(plane0));
344
345
6/12
✓ Branch 57 → 58 taken 6 times.
✗ Branch 57 → 148 not taken.
✓ Branch 59 → 60 taken 6 times.
✗ Branch 59 → 148 not taken.
✓ Branch 61 → 62 taken 6 times.
✗ Branch 61 → 148 not taken.
✓ Branch 63 → 64 taken 6 times.
✗ Branch 63 → 148 not taken.
✓ Branch 65 → 66 taken 6 times.
✗ Branch 65 → 148 not taken.
✓ Branch 66 → 67 taken 6 times.
✗ Branch 66 → 148 not taken.
6 env->BitBlt(dst->GetWritePtr(plane1), dst->GetPitch(plane1), srcp1,
346 frame->GetPitch(plane1), dst->GetRowSize(plane1), dst->GetHeight(plane1));
347
348
6/12
✓ Branch 68 → 69 taken 6 times.
✗ Branch 68 → 148 not taken.
✓ Branch 70 → 71 taken 6 times.
✗ Branch 70 → 148 not taken.
✓ Branch 72 → 73 taken 6 times.
✗ Branch 72 → 148 not taken.
✓ Branch 74 → 75 taken 6 times.
✗ Branch 74 → 148 not taken.
✓ Branch 76 → 77 taken 6 times.
✗ Branch 76 → 148 not taken.
✓ Branch 77 → 78 taken 6 times.
✗ Branch 77 → 148 not taken.
6 env->BitBlt(dst->GetWritePtr(plane2), dst->GetPitch(plane2), srcp2,
349 frame->GetPitch(plane2), dst->GetRowSize(plane2), dst->GetHeight(plane2));
350
351
2/2
✓ Branch 78 → 79 taken 1 time.
✓ Branch 78 → 94 taken 5 times.
6 if(hasAlpha)
352
8/16
✓ Branch 80 → 81 taken 1 time.
✗ Branch 80 → 148 not taken.
✓ Branch 82 → 83 taken 1 time.
✗ Branch 82 → 148 not taken.
✓ Branch 84 → 85 taken 1 time.
✗ Branch 84 → 148 not taken.
✓ Branch 86 → 87 taken 1 time.
✗ Branch 86 → 148 not taken.
✓ Branch 88 → 89 taken 1 time.
✗ Branch 88 → 148 not taken.
✓ Branch 90 → 91 taken 1 time.
✗ Branch 90 → 148 not taken.
✓ Branch 92 → 93 taken 1 time.
✗ Branch 92 → 148 not taken.
✓ Branch 93 → 94 taken 1 time.
✗ Branch 93 → 148 not taken.
1 env->BitBlt(dst->GetWritePtr(PLANAR_A), dst->GetPitch(PLANAR_A), frame->GetReadPtr(PLANAR_A) + top * frame->GetPitch(PLANAR_A) + left_bytes,
353 frame->GetPitch(PLANAR_A), dst->GetRowSize(PLANAR_A), dst->GetHeight(PLANAR_A));
354
355
1/2
✗ Branch 94 → 95 not taken.
✓ Branch 94 → 96 taken 6 times.
6 return dst;
356 }
357
358 // subframe is preserving frame properties
359 if (!frame->GetPitch(plane1))
360 return env->Subframe(frame, top * frame->GetPitch() + left_bytes, frame->GetPitch(), vi.RowSize(), vi.height);
361 else {
362 if (hasAlpha) {
363
364 return env->SubframePlanarA(frame, top * frame->GetPitch() + left_bytes, frame->GetPitch(), vi.RowSize(), vi.height,
365 (top >> ysub) * frame->GetPitch(plane1) + (left_bytes >> xsub),
366 (top >> ysub) * frame->GetPitch(plane2) + (left_bytes >> xsub),
367 frame->GetPitch(plane1), top * frame->GetPitch(PLANAR_A) + left_bytes);
368 }
369 else {
370 return env->SubframePlanar(frame, top * frame->GetPitch() + left_bytes, frame->GetPitch(), vi.RowSize(), vi.height,
371 (top >> ysub) * frame->GetPitch(plane1) + (left_bytes >> xsub),
372 (top >> ysub) * frame->GetPitch(plane2) + (left_bytes >> xsub),
373 frame->GetPitch(plane1));
374 }
375 }
376 6 }
377
378 1 int __stdcall Crop::SetCacheHints(int cachehints, int frame_range) {
379 AVS_UNUSED(frame_range);
380
1/3
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 4 not taken.
✗ Branch 2 → 6 not taken.
1 switch (cachehints) {
381 1 case CACHE_GET_MTMODE:
382 1 return MT_NICE_FILTER;
383 case CACHE_GET_DEV_TYPE:
384 return GetDeviceTypes(child) & (DEV_TYPE_CPU | DEV_TYPE_CUDA);
385 }
386 return 0;
387 }
388
389
390 AVSValue __cdecl Crop::Create(AVSValue args, void*, IScriptEnvironment* env)
391 {
392 return new Crop( args[1].AsInt(), args[2].AsInt(), args[3].AsInt(), args[4].AsInt(), args[5].AsBool(true),
393 args[0].AsClip(), env );
394 }
395
396
397
398
399
400 /******************************
401 ******* Add Borders ******
402 *****************************/
403
404 6 AddBorders::AddBorders(int _left, int _top, int _right, int _bot, int _clr, bool _force_color_as_yuv, PClip _child, IScriptEnvironment* env)
405 : GenericVideoFilter(_child),
406 6 left(max(0, _left)), top(max(0, _top)), right(max(0, _right)), bot(max(0, _bot)),
407 6 clr(_clr),
408 6 xsub(0), ysub(0),
409
2/4
✓ Branch 2 → 3 taken 6 times.
✗ Branch 2 → 40 not taken.
✓ Branch 3 → 4 taken 6 times.
✗ Branch 3 → 38 not taken.
6 force_color_as_yuv(_force_color_as_yuv)
410
411 {
412
8/10
✓ Branch 9 → 10 taken 6 times.
✗ Branch 9 → 41 not taken.
✓ Branch 10 → 11 taken 4 times.
✓ Branch 10 → 13 taken 2 times.
✓ Branch 11 → 12 taken 4 times.
✗ Branch 11 → 41 not taken.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 14 taken 3 times.
✓ Branch 15 → 16 taken 3 times.
✓ Branch 15 → 29 taken 3 times.
6 if (vi.IsYUV() || vi.IsYUVA()) {
413
2/4
✓ Branch 16 → 17 taken 3 times.
✗ Branch 16 → 41 not taken.
✓ Branch 17 → 18 taken 3 times.
✗ Branch 17 → 21 not taken.
3 if (vi.NumComponents() > 1) {
414
1/2
✓ Branch 18 → 19 taken 3 times.
✗ Branch 18 → 41 not taken.
3 xsub=vi.GetPlaneWidthSubsampling(PLANAR_U);
415
1/2
✓ Branch 19 → 20 taken 3 times.
✗ Branch 19 → 41 not taken.
3 ysub=vi.GetPlaneHeightSubsampling(PLANAR_U);
416 }
417
418 3 const int xmask = (1 << xsub) - 1;
419 3 const int ymask = (1 << ysub) - 1;
420
421 // YUY2, etc, ... can only add even amounts
422
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 3 times.
3 if (_left & xmask)
423 env->ThrowError("AddBorders: YUV image can only add by Mod %d (left side).", xmask+1);
424
1/2
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 3 times.
3 if (_right & xmask)
425 env->ThrowError("AddBorders: YUV image can only add by Mod %d (right side).", xmask+1);
426
427
1/2
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 3 times.
3 if (_top & ymask)
428 env->ThrowError("AddBorders: YUV image can only add by Mod %d (top).", ymask+1);
429
1/2
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 37 taken 3 times.
3 if (_bot & ymask)
430 env->ThrowError("AddBorders: YUV image can only add by Mod %d (bottom).", ymask+1);
431
7/10
✓ Branch 29 → 30 taken 3 times.
✗ Branch 29 → 41 not taken.
✓ Branch 30 → 31 taken 2 times.
✓ Branch 30 → 34 taken 1 time.
✓ Branch 31 → 32 taken 2 times.
✗ Branch 31 → 41 not taken.
✓ Branch 32 → 33 taken 2 times.
✗ Branch 32 → 34 not taken.
✓ Branch 35 → 36 taken 2 times.
✓ Branch 35 → 37 taken 1 time.
3 } else if (!vi.IsPlanarRGB() && !vi.IsPlanarRGBA()){
432 // RGB is upside-down
433 2 int t = top; top = bot; bot = t;
434 }
435 6 vi.width += left+right;
436 6 vi.height += top+bot;
437 6 }
438
439 template<typename pixel_t>
440 17 static inline pixel_t GetHbdColorFromByte(uint8_t color, bool fullscale, int bits_per_pixel, bool chroma)
441 {
442 10 if constexpr(sizeof(pixel_t) == 1) return color;
443
1/2
✓ Branch 2 → 3 taken 7 times.
✗ Branch 2 → 4 not taken.
7 else if constexpr(sizeof(pixel_t) == 2) return (pixel_t)(fullscale ? (color * ((1 << bits_per_pixel)-1)) / 255 : (int)color << (bits_per_pixel - 8));
444 else {
445 if (chroma)
446 return (pixel_t)uv8tof(color); // float, scale, 128=0.0f
447 else
448 return (pixel_t)c8tof(color); // float, scale to [0..1]
449 }
450 }
451
452 template<typename pixel_t>
453 4 static void addborders_planar(PVideoFrame &dst, PVideoFrame &src, VideoInfo &vi, int top, int bot, int left, int right, int color, bool isYUV, bool force_color_as_yuv, int bits_per_pixel)
454 {
455
3/18
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 6 not taken.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 6 not taken.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 54 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 6 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 3 times.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 54 not taken.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 1 time.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 6 not taken.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 54 not taken.
4 const unsigned int colr = isYUV && !force_color_as_yuv ? RGB2YUV_Rec601(color) : color;
456 4 const unsigned char YBlack=(unsigned char)((colr >> 16) & 0xff);
457 4 const unsigned char UBlack=(unsigned char)((colr >> 8) & 0xff);
458 4 const unsigned char VBlack=(unsigned char)((colr ) & 0xff);
459 4 const unsigned char ABlack=(unsigned char)((colr >> 24) & 0xff);
460
461 4 int planesYUV[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A };
462 4 int planesRGB[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A };
463
2/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 9 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 7 → 8 taken 3 times.
✗ Branch 7 → 9 not taken.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 1 time.
4 int *planes = isYUV ? planesYUV : planesRGB;
464 4 uint8_t colorsYUV[4] = { YBlack, UBlack, VBlack, ABlack };
465 4 uint8_t colorsRGB[4] = { UBlack, VBlack, YBlack, ABlack }; // mapping for planar RGB
466
2/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 10 → 11 taken 3 times.
✗ Branch 10 → 12 not taken.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 1 time.
4 uint8_t *colors = isYUV ? colorsYUV : colorsRGB;
467
6/12
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 51 → 52 not taken.
✗ Branch 51 → 54 not taken.
✗ Branch 52 → 14 not taken.
✗ Branch 52 → 53 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 51 → 52 taken 13 times.
✗ Branch 51 → 54 not taken.
✓ Branch 52 → 14 taken 10 times.
✓ Branch 52 → 53 taken 3 times.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 51 → 52 taken 4 times.
✗ Branch 51 → 54 not taken.
✓ Branch 52 → 14 taken 3 times.
✓ Branch 52 → 53 taken 1 time.
17 for (int p = 0; p < vi.NumComponents(); p++)
468 {
469 13 int plane = planes[p];
470
2/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 54 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 15 → 16 taken 10 times.
✗ Branch 15 → 54 not taken.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 15 → 16 taken 3 times.
✗ Branch 15 → 54 not taken.
13 int src_pitch = src->GetPitch(plane);
471
2/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 54 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 17 → 18 taken 10 times.
✗ Branch 17 → 54 not taken.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 17 → 18 taken 3 times.
✗ Branch 17 → 54 not taken.
13 int src_rowsize = src->GetRowSize(plane);
472
2/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 54 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 19 → 20 taken 10 times.
✗ Branch 19 → 54 not taken.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 19 → 20 taken 3 times.
✗ Branch 19 → 54 not taken.
13 int src_height = src->GetHeight(plane);
473
474
2/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 54 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 21 → 22 taken 10 times.
✗ Branch 21 → 54 not taken.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 21 → 22 taken 3 times.
✗ Branch 21 → 54 not taken.
13 int dst_pitch = dst->GetPitch(plane);
475
476
2/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 54 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 22 → 23 taken 10 times.
✗ Branch 22 → 54 not taken.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 22 → 23 taken 3 times.
✗ Branch 22 → 54 not taken.
13 int xsub=vi.GetPlaneWidthSubsampling(plane);
477
2/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 54 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 23 → 24 taken 10 times.
✗ Branch 23 → 54 not taken.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 23 → 24 taken 3 times.
✗ Branch 23 → 54 not taken.
13 int ysub=vi.GetPlaneHeightSubsampling(plane);
478
479
2/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 54 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 24 → 25 taken 10 times.
✗ Branch 24 → 54 not taken.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 24 → 25 taken 3 times.
✗ Branch 24 → 54 not taken.
13 const int initial_black = (top >> ysub) * dst_pitch + vi.BytesFromPixels(left >> xsub);
480 13 const int middle_black = dst_pitch - src_rowsize;
481
2/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 54 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 25 → 26 taken 10 times.
✗ Branch 25 → 54 not taken.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 25 → 26 taken 3 times.
✗ Branch 25 → 54 not taken.
13 const int final_black = (bot >> ysub) * dst_pitch + vi.BytesFromPixels(right >> xsub) +
482
2/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 54 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 27 → 28 taken 10 times.
✗ Branch 27 → 54 not taken.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 27 → 28 taken 3 times.
✗ Branch 27 → 54 not taken.
13 (dst_pitch - dst->GetRowSize(plane));
483
484
6/12
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 30 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 31 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 28 → 29 taken 7 times.
✓ Branch 28 → 30 taken 3 times.
✓ Branch 29 → 30 taken 3 times.
✓ Branch 29 → 31 taken 4 times.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 28 → 29 taken 3 times.
✗ Branch 28 → 30 not taken.
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 3 times.
13 const bool chroma = plane == PLANAR_U || plane == PLANAR_V;
485
486 13 pixel_t current_color = GetHbdColorFromByte<pixel_t>(colors[p], !isYUV, bits_per_pixel, chroma);
487
488
2/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 54 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 34 → 35 taken 10 times.
✗ Branch 34 → 54 not taken.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 34 → 35 taken 3 times.
✗ Branch 34 → 54 not taken.
13 BYTE *dstp = dst->GetWritePtr(plane);
489 // copy original
490
4/12
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 54 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 54 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 36 → 37 taken 10 times.
✗ Branch 36 → 54 not taken.
✓ Branch 37 → 38 taken 10 times.
✗ Branch 37 → 54 not taken.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 36 → 37 taken 3 times.
✗ Branch 36 → 54 not taken.
✓ Branch 37 → 38 taken 3 times.
✗ Branch 37 → 54 not taken.
13 BitBlt(dstp+initial_black, dst_pitch, src->GetReadPtr(plane), src_pitch, src_rowsize, src_height);
491 // add top
492
4/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 40 → 39 not taken.
✗ Branch 40 → 41 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 40 → 39 taken 1040 times.
✓ Branch 40 → 41 taken 10 times.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 40 → 39 taken 99 times.
✓ Branch 40 → 41 taken 3 times.
1152 for (size_t a = 0; a<initial_black / sizeof(pixel_t); a++) {
493 1139 reinterpret_cast<pixel_t *>(dstp)[a] = current_color;
494 }
495 // middle right + left (fill overflows from right to left)
496 13 dstp += initial_black + src_rowsize;
497
4/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 46 → 42 not taken.
✗ Branch 46 → 47 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 46 → 42 taken 19 times.
✓ Branch 46 → 47 taken 10 times.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 46 → 42 taken 6 times.
✓ Branch 46 → 47 taken 3 times.
38 for (int y = src_height-1; y>0; --y) {
498
4/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 44 → 43 not taken.
✗ Branch 44 → 45 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 44 → 43 taken 1112 times.
✓ Branch 44 → 45 taken 19 times.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 44 → 43 taken 162 times.
✓ Branch 44 → 45 taken 6 times.
1299 for (size_t b = 0; b<middle_black / sizeof(pixel_t); b++) {
499 1274 reinterpret_cast<pixel_t *>(dstp)[b] = current_color;
500 }
501 25 dstp += dst_pitch;
502 }
503 // bottom
504
4/6
void addborders_planar<float>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✗ Branch 49 → 48 not taken.
✗ Branch 49 → 50 not taken.
void addborders_planar<unsigned char>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 49 → 48 taken 1599 times.
✓ Branch 49 → 50 taken 10 times.
void addborders_planar<unsigned short>(PVideoFrame&, PVideoFrame&, VideoInfo&, int, int, int, int, int, bool, bool, int):
✓ Branch 49 → 48 taken 174 times.
✓ Branch 49 → 50 taken 3 times.
1786 for (size_t c = 0; c<final_black / sizeof(pixel_t); c++)
505 1773 reinterpret_cast<pixel_t *>(dstp)[c] = current_color;
506 }
507 4 }
508
509 6 PVideoFrame AddBorders::GetFrame(int n, IScriptEnvironment* env)
510 {
511
1/2
✓ Branch 3 → 4 taken 6 times.
✗ Branch 3 → 155 not taken.
6 PVideoFrame src = child->GetFrame(n, env);
512
1/2
✓ Branch 4 → 5 taken 6 times.
✗ Branch 4 → 153 not taken.
6 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
513
514
3/4
✓ Branch 5 → 6 taken 6 times.
✗ Branch 5 → 151 not taken.
✓ Branch 6 → 7 taken 4 times.
✓ Branch 6 → 23 taken 2 times.
6 if (vi.IsPlanar()) {
515
1/2
✓ Branch 7 → 8 taken 4 times.
✗ Branch 7 → 151 not taken.
4 int bits_per_pixel = vi.BitsPerComponent();
516
6/8
✓ Branch 8 → 9 taken 4 times.
✗ Branch 8 → 151 not taken.
✓ Branch 9 → 10 taken 2 times.
✓ Branch 9 → 12 taken 2 times.
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 151 not taken.
✓ Branch 11 → 12 taken 1 time.
✓ Branch 11 → 13 taken 1 time.
4 bool isYUV = vi.IsYUV() || vi.IsYUVA();
517
3/5
✓ Branch 14 → 15 taken 4 times.
✗ Branch 14 → 151 not taken.
✓ Branch 15 → 16 taken 3 times.
✓ Branch 15 → 18 taken 1 time.
✗ Branch 15 → 20 not taken.
4 switch(vi.ComponentSize()) {
518
1/2
✓ Branch 16 → 17 taken 3 times.
✗ Branch 16 → 151 not taken.
3 case 1: addborders_planar<uint8_t>(dst, src, vi, top, bot, left, right, clr, isYUV, force_color_as_yuv /*like MODE_COLOR_YUV in BlankClip */, bits_per_pixel); break;
519
1/2
✓ Branch 18 → 19 taken 1 time.
✗ Branch 18 → 151 not taken.
1 case 2: addborders_planar<uint16_t>(dst, src, vi, top, bot, left, right, clr, isYUV, force_color_as_yuv, bits_per_pixel); break;
520 default: //case 4:
521 addborders_planar<float>(dst, src, vi, top, bot, left, right, clr, isYUV, force_color_as_yuv, bits_per_pixel); break;
522 }
523 4 return dst;
524 }
525
526
1/2
✓ Branch 24 → 25 taken 2 times.
✗ Branch 24 → 151 not taken.
2 const BYTE* srcp = src->GetReadPtr();
527
1/2
✓ Branch 26 → 27 taken 2 times.
✗ Branch 26 → 151 not taken.
2 BYTE* dstp = dst->GetWritePtr();
528
1/2
✓ Branch 28 → 29 taken 2 times.
✗ Branch 28 → 151 not taken.
2 const int src_pitch = src->GetPitch();
529
1/2
✓ Branch 30 → 31 taken 2 times.
✗ Branch 30 → 151 not taken.
2 const int dst_pitch = dst->GetPitch();
530
1/2
✓ Branch 32 → 33 taken 2 times.
✗ Branch 32 → 151 not taken.
2 const int src_row_size = src->GetRowSize();
531
1/2
✓ Branch 34 → 35 taken 2 times.
✗ Branch 34 → 151 not taken.
2 const int dst_row_size = dst->GetRowSize();
532
1/2
✓ Branch 36 → 37 taken 2 times.
✗ Branch 36 → 151 not taken.
2 const int src_height = src->GetHeight();
533
534
1/2
✓ Branch 37 → 38 taken 2 times.
✗ Branch 37 → 151 not taken.
2 const int initial_black = top * dst_pitch + vi.BytesFromPixels(left);
535 2 const int middle_black = dst_pitch - src_row_size;
536
1/2
✓ Branch 38 → 39 taken 2 times.
✗ Branch 38 → 151 not taken.
2 const int final_black = bot * dst_pitch + vi.BytesFromPixels(right)
537 2 + (dst_pitch - dst_row_size);
538
539
2/4
✓ Branch 39 → 40 taken 2 times.
✗ Branch 39 → 151 not taken.
✗ Branch 40 → 41 not taken.
✓ Branch 40 → 58 taken 2 times.
2 if (vi.IsYUY2()) {
540 const unsigned int colr = force_color_as_yuv ? clr : RGB2YUV_Rec601(clr);
541 const uint32_t black = (colr>>16) * 0x010001 + ((colr>>8)&255) * 0x0100 + (colr&255) * 0x01000000;
542
543 BitBlt(dstp+initial_black, dst_pitch, srcp, src_pitch, src_row_size, src_height);
544 for (int a = 0; a<initial_black; a += 4) {
545 *(uint32_t*)(dstp+a) = black;
546 }
547 dstp += initial_black + src_row_size;
548 for (int y = src_height-1; y>0; --y) {
549 for (int b = 0; b<middle_black; b += 4) {
550 *(uint32_t*)(dstp+b) = black;
551 }
552 dstp += dst_pitch;
553 }
554 for (int c = 0; c<final_black; c += 4) {
555 *(uint32_t*)(dstp+c) = black;
556 }
557
3/4
✓ Branch 58 → 59 taken 2 times.
✗ Branch 58 → 151 not taken.
✓ Branch 59 → 60 taken 1 time.
✓ Branch 59 → 84 taken 1 time.
2 } else if (vi.IsRGB24()) {
558 1 const unsigned char clr0 = (unsigned char)(clr & 0xFF);
559 1 const unsigned short clr1 = (unsigned short)(clr >> 8);
560
1/2
✓ Branch 60 → 61 taken 1 time.
✗ Branch 60 → 151 not taken.
1 const int leftbytes = vi.BytesFromPixels(left);
561 1 const int leftrow = src_row_size + leftbytes;
562
1/2
✓ Branch 61 → 62 taken 1 time.
✗ Branch 61 → 151 not taken.
1 const int rightbytes = vi.BytesFromPixels(right);
563 1 const int rightrow = dst_pitch - dst_row_size + rightbytes;
564
565
1/2
✓ Branch 62 → 63 taken 1 time.
✗ Branch 62 → 151 not taken.
1 BitBlt(dstp+initial_black, dst_pitch, srcp, src_pitch, src_row_size, src_height);
566 /* Cannot use *_black optimisation as pitch may not be mod 3 */
567
2/2
✓ Branch 68 → 64 taken 2 times.
✓ Branch 68 → 69 taken 1 time.
3 for (int y = top; y>0; --y) {
568
2/2
✓ Branch 66 → 65 taken 16 times.
✓ Branch 66 → 67 taken 2 times.
18 for (int i = 0; i<dst_row_size; i += 3) {
569 16 dstp[i] = clr0;
570 16 *(uint16_t*)(dstp+i+1) = clr1;
571 }
572 2 dstp += dst_pitch;
573 }
574
2/2
✓ Branch 77 → 70 taken 3 times.
✓ Branch 77 → 78 taken 1 time.
4 for (int y = src_height; y>0; --y) {
575
2/2
✓ Branch 72 → 71 taken 3 times.
✓ Branch 72 → 73 taken 3 times.
6 for (int i = 0; i<leftbytes; i += 3) {
576 3 dstp[i] = clr0;
577 3 *(uint16_t*)(dstp+i+1) = clr1;
578 }
579 3 dstp += leftrow;
580
2/2
✓ Branch 75 → 74 taken 6 times.
✓ Branch 75 → 76 taken 3 times.
9 for (int i = 0; i<rightbytes; i += 3) {
581 6 dstp[i] = clr0;
582 6 *(uint16_t*)(dstp+i+1) = clr1;
583 }
584 3 dstp += rightrow;
585 }
586
2/2
✓ Branch 83 → 79 taken 1 time.
✓ Branch 83 → 147 taken 1 time.
2 for (int y = bot; y>0; --y) {
587
2/2
✓ Branch 81 → 80 taken 8 times.
✓ Branch 81 → 82 taken 1 time.
9 for (int i = 0; i<dst_row_size; i += 3) {
588 8 dstp[i] = clr0;
589 8 *(uint16_t*)(dstp+i+1) = clr1;
590 }
591 1 dstp += dst_pitch;
592 }
593 }
594
2/4
✓ Branch 84 → 85 taken 1 time.
✗ Branch 84 → 151 not taken.
✗ Branch 85 → 86 not taken.
✓ Branch 85 → 99 taken 1 time.
1 else if (vi.IsRGB32()) {
595 BitBlt(dstp+initial_black, dst_pitch, srcp, src_pitch, src_row_size, src_height);
596 for (int i = 0; i<initial_black; i += 4) {
597 *(uint32_t*)(dstp+i) = clr;
598 }
599 dstp += initial_black + src_row_size;
600 for (int y = src_height-1; y>0; --y) {
601 for (int i = 0; i<middle_black; i += 4) {
602 *(uint32_t*)(dstp+i) = clr;
603 }
604 dstp += dst_pitch;
605 } // for y
606 for (int i = 0; i<final_black; i += 4) {
607 *(uint32_t*)(dstp+i) = clr;
608 }
609
2/4
✓ Branch 99 → 100 taken 1 time.
✗ Branch 99 → 151 not taken.
✗ Branch 100 → 101 not taken.
✓ Branch 100 → 128 taken 1 time.
1 } else if (vi.IsRGB48()) {
610 const uint16_t clr0 = GetHbdColorFromByte<uint16_t>(clr & 0xFF, true, 16, false);
611 uint32_t clr1 =
612 ((uint32_t)GetHbdColorFromByte<uint16_t>((clr >> 16) & 0xFF, true, 16, false) << (8 * 2)) +
613 ((uint32_t)GetHbdColorFromByte<uint16_t>((clr >> 8) & 0xFF, true, 16, false));
614 const int leftbytes = vi.BytesFromPixels(left);
615 const int leftrow = src_row_size + leftbytes;
616 const int rightbytes = vi.BytesFromPixels(right);
617 const int rightrow = dst_pitch - dst_row_size + rightbytes;
618
619 BitBlt(dstp+initial_black, dst_pitch, srcp, src_pitch, src_row_size, src_height);
620 /* Cannot use *_black optimisation as pitch may not be mod 3 */
621 for (int y = top; y>0; --y) {
622 for (int i = 0; i<dst_row_size; i += 6) {
623 *(uint16_t*)(dstp+i) = clr0;
624 *(uint32_t*)(dstp+i+2) = clr1;
625 }
626 dstp += dst_pitch;
627 }
628 for (int y = src_height; y>0; --y) {
629 for (int i = 0; i<leftbytes; i += 6) {
630 *(uint16_t*)(dstp+i) = clr0;
631 *(uint32_t*)(dstp+i+2) = clr1;
632 }
633 dstp += leftrow;
634 for (int i = 0; i<rightbytes; i += 6) {
635 *(uint16_t*)(dstp+i) = clr0;
636 *(uint32_t*)(dstp+i+2) = clr1;
637 }
638 dstp += rightrow;
639 }
640 for (int y = bot; y>0; --y) {
641 for (int i = 0; i<dst_row_size; i += 6) {
642 *(uint16_t*)(dstp+i) = clr0;
643 *(uint32_t*)(dstp+i+2) = clr1;
644 }
645 dstp += dst_pitch;
646 }
647
2/4
✓ Branch 128 → 129 taken 1 time.
✗ Branch 128 → 151 not taken.
✓ Branch 129 → 130 taken 1 time.
✗ Branch 129 → 147 not taken.
1 } else if (vi.IsRGB64()) {
648
1/2
✓ Branch 130 → 131 taken 1 time.
✗ Branch 130 → 151 not taken.
1 BitBlt(dstp+initial_black, dst_pitch, srcp, src_pitch, src_row_size, src_height);
649
650 uint64_t clr64 =
651 1 ((uint64_t)GetHbdColorFromByte<uint16_t>((clr >> 24) & 0xFF, true, 16, false) << (24 * 2)) +
652 1 ((uint64_t)GetHbdColorFromByte<uint16_t>((clr >> 16) & 0xFF, true, 16, false) << (16 * 2)) +
653 1 ((uint64_t)GetHbdColorFromByte<uint16_t>((clr >> 8) & 0xFF, true, 16, false) << (8 * 2)) +
654 1 ((uint64_t)GetHbdColorFromByte<uint16_t>((clr) & 0xFF, true, 16, false));
655
656
2/2
✓ Branch 137 → 136 taken 9 times.
✓ Branch 137 → 138 taken 1 time.
10 for (int i = 0; i<initial_black; i += 8) {
657 9 *(uint64_t*)(dstp+i) = clr64;
658 }
659 1 dstp += initial_black + src_row_size;
660
2/2
✓ Branch 143 → 139 taken 2 times.
✓ Branch 143 → 144 taken 1 time.
3 for (int y = src_height-1; y>0; --y) {
661
2/2
✓ Branch 141 → 140 taken 10 times.
✓ Branch 141 → 142 taken 2 times.
12 for (int i = 0; i<middle_black; i += 8) {
662 10 *(uint64_t*)(dstp+i) = clr64;
663 }
664 2 dstp += dst_pitch;
665 } // for y
666
2/2
✓ Branch 146 → 145 taken 12 times.
✓ Branch 146 → 147 taken 1 time.
13 for (int i = 0; i<final_black; i += 8) {
667 12 *(uint64_t*)(dstp+i) = clr64;
668 }
669 }
670
671 2 return dst;
672 6 }
673
674 // Optional transient area filtering when radius > 0
675 // The primary aim to blur the border neighborhood to prevent excessive ringing on
676 // a following upscaleing process
677 static PClip AddBorderPostProcess(PClip child,
678 int left, int top, int right, int bottom,
679 const AVSValue& _resample, const AVSValue& _param1, const AVSValue& _param2, const AVSValue& _param3, const AVSValue& _flt_rad,
680 int forced_chroma_placement,
681 IScriptEnvironment* env) {
682
683 // filtering radius, default 0: no transient area filtering
684 int r = _flt_rad.AsInt(0);
685
686 if (r == 0)
687 return child;
688
689 // Default: only the border side gets the blur treatment
690 // Minus "r": only the outer - added border - part is blurred
691 // though this is usually not enough to prevent ringing when upscaling.
692 const bool both_side = (r > 0);
693 if (r < 0)
694 r = -r;
695
696 const VideoInfo& vi = child->GetVideoInfo();
697
698 /*if (vi.IsYUY2())
699 env->ThrowError("AddBorders: YUY2 transient filtering not supported, use YV16.");
700 */
701
702 AVSValue param1 = _param1;
703 AVSValue param2 = _param2;
704 AVSValue param3 = _param3;
705
706 // evaluate resample parameters only radius > 0
707 const char* resampler_name = _resample.AsString("gauss");
708 if (_stricmp(resampler_name, "gauss") == 0) {
709 // for gauss, defaults are different from what we use in chroma resamplers.
710 // here we use this filter for blurring (convolution use)
711 // p = 10, b = 2.71828, s = 0
712 param1 = _param1.AsDblDef(10); // p
713 param2 = _param2.AsDblDef(2.718281828); // b
714 param3 = _param3.AsDblDef(0); // 0
715 }
716 ResamplingFunction* filter = getResampler(resampler_name, param1, param2, param3, false, env);
717 if (filter == nullptr)
718 env->ThrowError("AddBorders: unknown resampler name: %s", resampler_name);
719
720 const bool grey = vi.IsY();
721 const bool isRGBPfamily = vi.IsPlanarRGB() || vi.IsPlanarRGBA();
722
723 const int shift_w = (vi.IsPlanar() && !grey && !isRGBPfamily) ? vi.GetPlaneWidthSubsampling(PLANAR_U) : 0;
724 const int shift_h = (vi.IsPlanar() && !grey && !isRGBPfamily) ? vi.GetPlaneHeightSubsampling(PLANAR_U) : 0;
725 const int shift = max(shift_w, shift_h); // worst case
726
727 // adjust radius for worst case chroma
728 r = (r + (1 << shift) - 1) & ~((1 << shift) - 1); // chroma friendly
729
730 const int MIN_FILTERING_EXTENT = 10; // +/-
731 // but if one of the margins are smaller, e.g. 5, the the 2*10 is achieved as 5+15 pixel wide (high) parts
732 // We always filter a larger area, but only copy the 2*radius (r) pixels from it.
733 // a radius plus the filter support size overrides
734 int filtering_width = max(MIN_FILTERING_EXTENT, r + (int)std::ceil(filter->support()));
735
736 // adjust the filtering width for the worst case, considering the chroma subsampling
737 filtering_width = (filtering_width + (1 << shift) - 1) & ~((1 << shift) - 1);
738 // active area before adding the new borders
739 const int orig_width = vi.width - left - right;
740 const int orig_height = vi.height - top - bottom;
741
742 // End of safety adjustments
743 // Radius "r" and "filtering_width" are both +/- values and are chroma and resizer friendly.
744 // left, right, top, bottom are already chroma subsample friendly values
745
746 /*
747 Create up to 8 sections.
748
749 left, top, right, bottom and the four corner bars mark the convolution (blur) area.
750 - left and right needs only force horizontal resizer
751 - top and bottom bars force vertical resizer
752 - corners force both H and V resizer
753 +---+-------------------+
754 | oo|ooooooooooooooo|oo |
755 +-o-+-----------------o-+
756 | o | | o |
757 | o | | o |
758 | o | | o |
759 | o | | o |
760 | o | | o |
761 | o | | o |
762 +-o-+---------------+-o-+
763 | oo|ooooooooooooooo|oo |
764 +---+---------------+---+
765 */
766
767 typedef struct {
768 PClip clip; // a smart pointer
769 int extent_outer_horiz, extent_inner_horiz; // may not be symmetric
770 int extent_outer_vert, extent_inner_vert;
771 int crop_x, crop_y;
772 int target_x, target_y;
773 int target_width, target_height;
774 int src_x, src_y;
775 int src_width, src_height;
776 int force;
777 // 0 - return unchanged if no resize needed
778 // 1 - force H - Horizontal resizing phase, For vertical bars
779 // 2 - force V - Vertical resizing phase, For horizontal bars
780 // 3 - force H and V for corner rectangles
781 } BarSection;
782
783 std::vector<BarSection> bars;
784
785 /* Example on LEFT and RIGHT vertical bar
786
787 extent_outer extent_inner extent_inner extent_outer
788 <------>|<---------> <------>|<--------->
789
790 r*2 r*2
791 |<>|<>| orig_width |<>|<>|
792 <------------------------------------>
793 +----+--|--+-------+ ^ +----+--|--+-------+
794 | | | | | | | | | | |
795 | | | | | |orig_height | | | | |
796 | | | | | | | | | | |
797 | | | | | | | | | | |
798 | | | | | | | | | | |
799 +----+--|--+-------+ V +----+--|--+-------+
800
801 The extent_inner+extent_outer area is cropped and blurred (filtered) with the given algoritm, e.g "gauss".
802 From this blurred Clip only the (2*r) * orig_height rectangle is copied back onto the transient area.
803 */
804
805 // Define bar sections data for iteration
806
807 struct BarSectionTemplate {
808 int side; // 0=left, 1=right, 2=top, 3=bottom 4=top-left 5=top-right 6=bottom-left 7=bottom-right
809 int direction; // 1=horizontally, 2=vertically filtere, 3=both (corners)
810 };
811
812 const BarSectionTemplate templates[] = {
813 {0, 1}, // left bar (horizontally filtered)
814 {1, 1}, // right bar (horizontally filtered)
815 {2, 2}, // top bar (vertically filtered)
816 {3, 2}, // bottom bar (vertically filtered)
817 {4, 3}, // top left rectangle (H-V filtered)
818 {5, 3}, // top right rectangle (H-V filtered)
819 {6, 3}, // bottom left rectangle (H-V filtered)
820 {7, 3} // bottom right rectangle (H-V filtered)
821 };
822
823 // First cycle: initialize common parameters and calculate dimensions
824 for (int i = 0; i < 8; i++) {
825 BarSection bar = {};
826
827 const bool isHorizontallyFiltered = (templates[i].direction == 1) || (templates[i].direction == 3);
828 const bool isVerticallyFiltered = (templates[i].direction == 2) || (templates[i].direction == 3);
829 const int side = templates[i].side;
830
831 // Calculate border to use based on side
832 int borderSize, borderSize2;
833 switch (side) {
834 case 0: borderSize = left; borderSize2 = 0; break;
835 case 1: borderSize = right; borderSize2 = 0; break;
836 case 2: borderSize = 0; borderSize2 = top; break;
837 case 3: borderSize = 0; borderSize2 = bottom; break;
838 case 4: borderSize = left; borderSize2 = top; break;
839 case 5: borderSize = right; borderSize2 = top; break;
840 case 6: borderSize = left; borderSize2 = bottom; break;
841 case 7: borderSize = right; borderSize2 = bottom; break;
842 }
843
844 int safe_flt_rad = r;
845 if (borderSize > 0) { // same as isHorizontallyFiltered
846 bar.extent_outer_horiz = std::min(filtering_width, borderSize);
847 bar.extent_inner_horiz = 2 * filtering_width - bar.extent_outer_horiz;
848 }
849 if (borderSize2 > 0) { // same as(isVerticallyFiltered
850 bar.extent_outer_vert = std::min(filtering_width, borderSize2);
851 bar.extent_inner_vert = 2 * filtering_width - bar.extent_outer_vert;
852 }
853
854 if (isHorizontallyFiltered) {
855 safe_flt_rad = std::min(safe_flt_rad, borderSize);
856 bar.extent_inner_horiz = std::min(bar.extent_inner_horiz, orig_width);
857 }
858 if (isVerticallyFiltered) {
859 safe_flt_rad = std::min(safe_flt_rad, borderSize2);
860 bar.extent_inner_vert = std::min(bar.extent_inner_vert, orig_height);
861 }
862
863 int safe_flt_rad_inner = both_side ? safe_flt_rad : 0;
864
865 int safe_flt_rad_inner_horiz = std::min(bar.extent_inner_horiz, safe_flt_rad_inner);
866 int safe_flt_rad_inner_vert = std::min(bar.extent_inner_vert, safe_flt_rad_inner);
867
868 // Set force direction
869 bar.force = templates[i].direction;
870
871 // Set dimensions based on direction and side
872 if (isHorizontallyFiltered && isVerticallyFiltered) { // corners
873 bar.target_width = bar.extent_outer_horiz + bar.extent_inner_horiz;
874 bar.target_height = bar.extent_outer_vert + bar.extent_inner_vert;
875 bar.src_width = safe_flt_rad + safe_flt_rad_inner_horiz;
876 bar.src_height = safe_flt_rad + safe_flt_rad_inner_vert;
877
878 if (side == 4 || side == 6) { // Top Left Bottom Left
879 bar.crop_x = left - bar.extent_outer_horiz;
880 bar.target_x = left - safe_flt_rad;
881 bar.src_x = bar.extent_outer_horiz - safe_flt_rad;
882 }
883 else { // Top Right Bottom Right
884 bar.crop_x = left + orig_width - bar.extent_inner_horiz;
885 bar.target_x = left + orig_width - safe_flt_rad_inner_horiz;
886 bar.src_x = bar.extent_inner_horiz - safe_flt_rad_inner_horiz;
887 }
888
889 if (side == 4 || side == 5) { // Top Left Top Right
890 bar.crop_y = top - bar.extent_outer_vert;
891 bar.target_y = top - safe_flt_rad;
892 bar.src_y = bar.extent_outer_vert - safe_flt_rad;
893 }
894 else { // Bottom Left Bottom Right
895 bar.crop_y = top + orig_height - bar.extent_inner_vert;
896 bar.target_y = top + orig_height - safe_flt_rad_inner_vert;
897 bar.src_y = bar.extent_inner_vert - safe_flt_rad_inner_vert;
898 }
899 }
900 else if (isHorizontallyFiltered) {
901 // Vertical but horizontally filtered bars on the left/right side
902 bar.target_width = bar.extent_outer_horiz + bar.extent_inner_horiz;
903 bar.target_height = orig_height;
904 bar.src_width = safe_flt_rad + safe_flt_rad_inner_horiz;
905 bar.src_height = orig_height;
906
907 if (side == 0) { // Left
908 bar.crop_x = left - bar.extent_outer_horiz;;
909 bar.crop_y = top;
910 bar.target_x = left - safe_flt_rad;
911 bar.target_y = top;
912 bar.src_x = bar.extent_outer_horiz - safe_flt_rad;
913
914 }
915 else { // Right
916 bar.crop_x = left + orig_width - bar.extent_inner_horiz;
917 bar.crop_y = top;
918 bar.target_x = left + orig_width - safe_flt_rad_inner_horiz;
919 bar.target_y = top;
920 bar.src_x = bar.extent_inner_horiz - safe_flt_rad_inner_horiz;
921 }
922
923 bar.src_y = 0;
924 }
925 else {
926 // Horizontal, but vertically filtered bars (top/bottom)
927 bar.target_width = orig_width;
928 bar.target_height = bar.extent_outer_vert + bar.extent_inner_vert;
929 bar.src_width = orig_width;
930 bar.src_height = safe_flt_rad + safe_flt_rad_inner_vert;
931
932 if (side == 2) { // Top
933 bar.crop_x = left;
934 bar.crop_y = top - bar.extent_outer_vert;
935 bar.target_x = left;
936 bar.target_y = top - safe_flt_rad;
937 bar.src_y = bar.extent_outer_vert - safe_flt_rad;
938 }
939 else { // Bottom
940 bar.crop_x = left;
941 bar.crop_y = top + orig_height - bar.extent_inner_vert;
942 bar.target_x = left;
943 bar.target_y = top + orig_height - safe_flt_rad_inner_vert;
944 bar.src_y = bar.extent_inner_vert - safe_flt_rad_inner_vert;
945 }
946
947 bar.src_x = 0;
948 }
949
950 // avoid "Resize: Source image too small for this resize method. Width=%d, Support=%d", source_size, int(ceil(filter_support))"
951 // int source_size, double crop_size, int target_size
952 // all are the same here
953 // whether H or V resizing is forced, only check for that dimension
954 bool ok = true;
955 if (isHorizontallyFiltered && bar.target_width <= 0) ok = false;
956 if (isVerticallyFiltered && bar.target_height <= 0) ok = false;
957 // size is indifferent since avs 3.7.4, resizers are robust, accept anything,
958 // no other size constraint check is needed.
959
960 if(ok)
961 bars.push_back(bar);
962 }
963
964 std::vector<PClip> child_array = { child };
965 std::vector<int> position_array = { };
966
967 const bool preserve_center = true;
968 const char* placement_name = nullptr;
969 // along with forced_chroma_placement, does not read frame props again in eight child resizers
970 // _ChromaLocation - if any - was read in AddBorders - once - and passed here
971
972 for (auto& bar : bars) {
973 // or use [src_left]f[src_top]f[src_width]f[src_height]f
974 // resizer parameters set for convolution (unchanged dimensions) filter
975 /* When we directly pass source position, it's not possible to govern the directional "force", anyway, it would just call crop as well.
976 AVSValue args_left_top_w_h[4] = {bar.crop_x, bar.crop_y, bar.target_width, bar.target_height}; // left, top, width (auto), height (auto)
977 bar.clip = FilteredResize::CreateResize(child, bar.target_width, bar.target_height, args_left_top_w_h, bar.force, filter, env);
978 */
979 AVSValue args_left_top_w_h[4] = { 0, 0, AVSValue(), AVSValue() }; // left, top, width (auto), height (auto)
980
981 bar.clip = FilteredResize::CreateResize(
982 new Crop(bar.crop_x, bar.crop_y, bar.target_width, bar.target_height, 0, child, env),
983 bar.target_width, bar.target_height, args_left_top_w_h, bar.force, filter,
984 preserve_center, placement_name, forced_chroma_placement,
985 env);
986
987
988 // Add to vector
989 child_array.push_back(bar.clip);
990 position_array.push_back(bar.target_x);
991 position_array.push_back(bar.target_y);
992 // we can copy only a smaller part from the filtered area
993 // After blurring e.g. a 10x10 rectangle, we'd copy only from a radius of +/-1 or +/-2
994 position_array.push_back(bar.src_x);
995 position_array.push_back(bar.src_y);
996 position_array.push_back(bar.src_width);
997 position_array.push_back(bar.src_height);
998 }
999
1000 PClip clip = new MultiOverlay(child_array, position_array, env);
1001
1002 delete filter;
1003
1004 return clip;
1005 }
1006
1007
1008 AVSValue __cdecl AddBorders::Create(AVSValue args, void*, IScriptEnvironment* env)
1009 {
1010 // [0][1][2][3][4] [5] [6] [7] [8] [9] [10] [11]
1011 // c i i i i [color]i[color_yuv]i[resample]s[param1]f[param2]f[param3]f[r]i
1012 // int left, int top, int right, int bottom
1013
1014 // similar to BlankClip
1015 int color = args[5].AsInt(0);
1016 bool color_as_yuv = false;
1017
1018 const VideoInfo& vi = args[0].AsClip()->GetVideoInfo();
1019
1020 if (args[6].Defined()) {
1021 if (color != 0) // Not quite 100% test
1022 env->ThrowError("AddBorders: color and color_yuv are mutually exclusive");
1023
1024 if (!vi.IsYUV() && !vi.IsYUVA())
1025 env->ThrowError("AddBorders: color_yuv only valid for YUV color spaces");
1026 color = args[6].AsInt(); // override
1027 color_as_yuv = true;
1028 }
1029
1030 const int left = max(0, args[1].AsInt());
1031 const int top = max(0, args[2].AsInt());
1032 const int right = max(0, args[3].AsInt());
1033 const int bottom = max(0, args[4].AsInt());
1034
1035 int forced_chroma_placement = ChromaLocation_e::AVS_CHROMA_UNUSED;
1036 if (vi.IsYV411() || vi.Is420() || vi.Is422()) {
1037 auto frame0 = args[0].AsClip()->GetFrame(0, env);
1038 const AVSMap* props = env->getFramePropsRO(frame0);
1039 if (props) {
1040 if (env->propNumElements(props, "_ChromaLocation") > 0) {
1041 forced_chroma_placement = (int)env->propGetIntSaturated(props, "_ChromaLocation", 0, nullptr);
1042 }
1043 }
1044 }
1045
1046 // here we have read _ChromaLocation, in order to pass it directly to the many blurring resizers to prevent them
1047 // to read up to 8x GetFrame(0) in their init for getting the same frame properties like we had.
1048
1049 PClip clip = new AddBorders( left, top, right, bottom, color, color_as_yuv, args[0].AsClip(), env);
1050
1051 // args[7], args[8], args[9], args[10], args[11], // [resample]s[param1]f[param2]f[param3]f[r]i
1052
1053 clip = AddBorderPostProcess(clip, left, top, right, bottom, args[7], args[8], args[9], args[10], args[11], forced_chroma_placement, env);
1054
1055 return clip;
1056 }
1057
1058
1059 /**********************************
1060 ******* Factory Methods ******
1061 *********************************/
1062
1063
1064 AVSValue __cdecl Create_Letterbox(AVSValue args, void*, IScriptEnvironment* env)
1065 {
1066 PClip clip = args[0].AsClip();
1067 int top = args[1].AsInt();
1068 int bottom = args[2].AsInt();
1069 int left = args[3].AsInt(0);
1070 int right = args[4].AsInt(0);
1071 int color = args[5].AsInt(0);
1072 const VideoInfo& vi = clip->GetVideoInfo();
1073
1074 // [0][1][2][3] [4] [5] [6] [7] [8] [9] [10] [11]
1075 // c i i [x1]i [x2]i [color]i [color_yuv]i[resample]s[param1]f[param2]f[param3]f[r]i
1076 // top, bottom, [left], [right] [,color] [,color_yuv]
1077
1078 // similar to BlankClip/AddBorders
1079 bool color_as_yuv = false;
1080 if (args[6].Defined()) {
1081 if (color != 0) // Not quite 100% test
1082 env->ThrowError("LetterBox: color and color_yuv are mutually exclusive");
1083
1084 if (!vi.IsYUV() && !vi.IsYUVA())
1085 env->ThrowError("LetterBox: color_yuv only valid for YUV color spaces");
1086 color = args[6].AsInt(); // override
1087 color_as_yuv = true;
1088 }
1089
1090 if ( (top<0) || (bottom<0) || (left<0) || (right<0) )
1091 env->ThrowError("LetterBox: You cannot specify letterboxing less than 0.");
1092 if (top+bottom>=vi.height) // Must be >= otherwise it is interpreted wrong by crop()
1093 env->ThrowError("LetterBox: You cannot specify letterboxing that is bigger than the picture (height).");
1094 if (right+left>=vi.width) // Must be >= otherwise it is interpreted wrong by crop()
1095 env->ThrowError("LetterBox: You cannot specify letterboxing that is bigger than the picture (width).");
1096
1097 if (vi.IsYUV() || vi.IsYUVA()) {
1098 int xsub = 0;
1099 int ysub = 0;
1100
1101 if (vi.NumComponents() > 1) {
1102 xsub=vi.GetPlaneWidthSubsampling(PLANAR_U);
1103 ysub=vi.GetPlaneHeightSubsampling(PLANAR_U);
1104 }
1105 const int xmask = (1 << xsub) - 1;
1106 const int ymask = (1 << ysub) - 1;
1107
1108 // YUY2, etc, ... can only operate to even pixel boundaries
1109 if (left & xmask)
1110 env->ThrowError("LetterBox: YUV images width must be divideable by %d (left side).", xmask+1);
1111 if (right & xmask)
1112 env->ThrowError("LetterBox: YUV images width must be divideable by %d (right side).", xmask+1);
1113
1114 if (top & ymask)
1115 env->ThrowError("LetterBox: YUV images height must be divideable by %d (top).", ymask+1);
1116 if (bottom & ymask)
1117 env->ThrowError("LetterBox: YUV images height must be divideable by %d (bottom).", ymask+1);
1118 }
1119
1120 left = max(0, left);
1121 top = max(0, top);
1122 right = max(0, right);
1123 bottom = max(0, bottom);
1124
1125 int forced_chroma_placement = ChromaLocation_e::AVS_CHROMA_UNUSED;
1126 if (vi.IsYV411() || vi.Is420() || vi.Is422()) {
1127 auto frame0 = clip->GetFrame(0, env);
1128 const AVSMap* props = env->getFramePropsRO(frame0);
1129 if (props) {
1130 if (env->propNumElements(props, "_ChromaLocation") > 0) {
1131 forced_chroma_placement = (int)env->propGetIntSaturated(props, "_ChromaLocation", 0, nullptr);
1132 }
1133 }
1134 }
1135
1136 clip = new AddBorders(left, top, right, bottom, color, color_as_yuv, new Crop(left, top, vi.width-left-right, vi.height-top-bottom, 0, clip, env), env);
1137
1138 // args[7], args[8], args[9], args[10], args[11], // [resample]s[param1]f[param2]f[param3]f[r]i
1139
1140 clip = AddBorderPostProcess(clip, left, top, right, bottom, args[7], args[8], args[9], args[10], args[11], forced_chroma_placement, env);
1141
1142 return clip;
1143
1144 }
1145
1146
1147 AVSValue __cdecl Create_CropBottom(AVSValue args, void*, IScriptEnvironment* env)
1148 {
1149 PClip clip = args[0].AsClip();
1150 const VideoInfo& vi = clip->GetVideoInfo();
1151 return new Crop(0, 0, vi.width, vi.height - args[1].AsInt(), 0, clip, env);
1152 }
1153