GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 93.4% 85 / 0 / 91
Functions: 100.0% 13 / 0 / 13
Branches: 68.9% 51 / 0 / 74

filters/overlay/imghelpers.h
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 // Overlay (c) 2003, 2004 by Klaus Post
36
37 #ifndef __Overlay_helpers_h
38 #define __Overlay_helpers_h
39
40 #include <avisynth.h>
41 #include <avs/minmax.h>
42 #include <avs/alignment.h>
43 #include "444convert.h"
44 #include "blend_common.h"
45
46 class ImageOverlayInternal {
47 private:
48 IScriptEnvironment* Env;
49
50 PVideoFrame &frame;
51
52 BYTE* origPlanes[4];
53 BYTE* fakePlanes[4];
54
55 int fake_w;
56 int fake_h;
57 int fake_x_accum; // cumulative luma x offset from all SubFrame calls
58 int fake_y_accum; // cumulative luma y offset from all SubFrame calls
59 const int _w;
60 const int _h;
61 const int _bits_per_pixel;
62 const bool grey;
63
64 bool return_original;
65
66 const int planes_y[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A };
67 const int planes_r[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A };
68 const int *planes;
69
70 int planeCount;
71 int pitches[4];
72
73 BYTE *maskChroma;
74 public:
75 int xSubSamplingShifts[4];
76 int ySubSamplingShifts[4];
77 int pitch;
78 int pitchUV;
79 int pitchA;
80
81 109 ImageOverlayInternal(
82 PVideoFrame &_frame,
83 109 int _inw, int _inh, VideoInfo &_workingVI, bool _hasAlpha, bool _grey, IScriptEnvironment* env) :
84 109 Env(env),
85 109 frame(_frame),
86 109 _w(_inw), _h(_inh), _bits_per_pixel(_workingVI.BitsPerComponent()), grey(_grey), maskChroma(nullptr) {
87
88 109 planeCount = _workingVI.NumComponents();
89
90
4/4
✓ Branch 5 → 6 taken 26 times.
✓ Branch 5 → 8 taken 83 times.
✓ Branch 7 → 8 taken 10 times.
✓ Branch 7 → 9 taken 16 times.
109 planes = (_workingVI.IsYUV() || _workingVI.IsYUVA()) ? planes_y : planes_r;
91
2/2
✓ Branch 12 → 11 taken 436 times.
✓ Branch 12 → 13 taken 109 times.
545 for (int p = 0; p < 4; p++) {
92 436 xSubSamplingShifts[p] = ySubSamplingShifts[p] = 0;
93 436 pitches[p] = 0;
94 }
95
96
2/2
✓ Branch 19 → 14 taken 337 times.
✓ Branch 19 → 20 taken 109 times.
446 for (int p = 0; p < planeCount; ++p) {
97 337 const int plane = planes[p];
98 337 xSubSamplingShifts[p] = _workingVI.GetPlaneWidthSubsampling(plane);
99 337 ySubSamplingShifts[p] = _workingVI.GetPlaneHeightSubsampling(plane);
100 337 pitches[p] = frame->GetPitch(plane);
101 }
102
103 // Set chroma pitches for greymask mode.
104 // All paths now use the luma pitch for chroma planes — no separate chroma buffer.
105
2/2
✓ Branch 20 → 21 taken 15 times.
✓ Branch 20 → 22 taken 94 times.
109 if (grey) {
106 15 pitches[1] = pitches[2] = pitches[0];
107 }
108
109 // temporarily. so far only blend is ported to arrays
110 109 pitch = pitches[0];
111 109 pitchUV = pitches[1];
112 109 pitchA = pitches[3];
113
114
2/2
✓ Branch 26 → 23 taken 337 times.
✓ Branch 26 → 27 taken 109 times.
446 for (int p = 0; p < planeCount; p++)
115 337 origPlanes[p] = (BYTE*)frame->GetReadPtr(planes[p]);
116
2/2
✓ Branch 27 → 28 taken 15 times.
✓ Branch 27 → 37 taken 94 times.
109 if (grey) {
117
6/6
✓ Branch 29 → 30 taken 13 times.
✓ Branch 29 → 32 taken 2 times.
✓ Branch 31 → 32 taken 1 time.
✓ Branch 31 → 33 taken 12 times.
✓ Branch 34 → 35 taken 3 times.
✓ Branch 34 → 36 taken 12 times.
15 if (_workingVI.Is420() || _workingVI.Is422()) {
118 // Chroma planes alias the luma plane. BlendImageMask (Overlay Blend/Luma/Chroma —
119 // the only modes that reach this branch with use444=false for subsampled YUV)
120 // computes placement-correct spatial averages per row into a per-row scratch buffer.
121 // xSubSamplingShifts[1/2] remain at their actual values (1) so callers can derive
122 // chroma dimensions and advance the luma-resolution mask row pointer correctly.
123 3 origPlanes[1] = origPlanes[2] = origPlanes[0];
124
125 // -------------------------------------------------------------------
126 // Historical: former per-frame chroma-mask pre-resampling (removed).
127 // ConvertYToYV12Chroma / ConvertYToYV16Chroma were called here once per
128 // frame to produce a pre-downsampled chroma-resolution mask plane stored
129 // in the maskChroma allocation. Removed due to several limitations:
130 //
131 // 1. MPEG1 (centre) chroma placement only. The converters averaged
132 // horizontally centred pairs of luma pixels, which corresponds to
133 // MPEG1/JPEG placement. MPEG2 (left-aligned / co-sited) placement
134 // — the default for H.262, H.264, and most broadcast content — was
135 // never supported; callers used the result regardless.
136 //
137 // 2. SIMD path was not bit-exact with the C path. The SSE2 variant
138 // used the avg_epu8( avg_epu8(a,b), avg_epu8(a^1,b^1) ) trick
139 // to approximate unbiased rounding, while the C fallback used plain
140 // (a+b+1)>>1. Results could differ by ±1 LSB.
141 //
142 // 3. No YV411 (4:1:1) support. No ConvertYToYV411Chroma function
143 // existed, so a greymask + YV411 blend in subsampled mode would
144 // have silently produced wrong output (chroma planes pointing at
145 // luma data without any horizontal averaging applied).
146 //
147 // 4. Only Overlay Blend, Luma, and Chroma with subsampled (420/422)
148 // YUV input and use444=false ever reached this code. All other
149 // modes are blocked from use444=false with YUV input:
150 // - Multiply, Darken, Lighten, SoftLight, HardLight, Difference,
151 // Exclusion: overlay.cpp throws "cannot specify use444=false
152 // for this overlay mode" at construction time.
153 // - Add, Subtract: use444=false is auto-set only for RGB input
154 // (lines 203-208 of overlay.cpp); for YUV these modes stay on
155 // the use444=true path and their ImageOverlayInternal is always
156 // created with a 4:4:4 working format.
157 // maskChroma (the BYTE* member) and its ~ImageOverlayInternal check
158 // are preserved below so the historical code compiles.
159 // -------------------------------------------------------------------
160 #if 0
161 // 4:2:0 former path
162 {
163 int pixelsize;
164 if (_bits_per_pixel == 8) pixelsize = 1;
165 else if (_bits_per_pixel <= 16) pixelsize = 2;
166 else pixelsize = 4;
167
168 int tmppitch = AlignNumber((_w >> xSubSamplingShifts[1]) * pixelsize, FRAME_ALIGN);
169 maskChroma = static_cast<BYTE*>(Env->Allocate(
170 tmppitch * (_h >> ySubSamplingShifts[1]), 64, AVS_POOLED_ALLOC));
171 pitches[1] = pitches[2] = tmppitch;
172 ConvertYToYV12Chroma(maskChroma, origPlanes[0], pitches[1], pitches[0], pixelsize,
173 _w >> xSubSamplingShifts[1], _h >> ySubSamplingShifts[1], Env);
174 origPlanes[1] = origPlanes[2] = maskChroma;
175 }
176 // 4:2:2 former path
177 {
178 int tmppitch = AlignNumber((_w >> xSubSamplingShifts[1]) * pixelsize, FRAME_ALIGN);
179 maskChroma = static_cast<BYTE*>(Env->Allocate(
180 tmppitch * (_h >> ySubSamplingShifts[1]), 64, AVS_POOLED_ALLOC));
181 pitches[1] = pitches[2] = tmppitch;
182 ConvertYToYV16Chroma(maskChroma, origPlanes[0], pitches[1], pitches[0], pixelsize,
183 _w >> xSubSamplingShifts[1], _h >> ySubSamplingShifts[1], Env);
184 origPlanes[1] = origPlanes[2] = maskChroma;
185 }
186 #endif
187 }
188 else {
189 // 444 / RGB / YV411 (no dedicated converter): UV = Y plane pointer.
190 12 origPlanes[1] = origPlanes[2] = origPlanes[0];
191 12 xSubSamplingShifts[1] = xSubSamplingShifts[2] = 0;
192 12 ySubSamplingShifts[1] = ySubSamplingShifts[2] = 0;
193 }
194 }
195
196 109 ResetFake();
197 109 }
198
199
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 466 times.
466 __inline int w() { return (return_original) ? _w : fake_w; }
200
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 466 times.
466 __inline int h() { return (return_original) ? _h : fake_h; }
201
202 183 BYTE* GetPtr(int plane) {
203
1/2
✓ Branch 2 → 3 taken 183 times.
✗ Branch 2 → 4 not taken.
183 if (!(_w && _h)) {
204 _RPT0(1,"Image444: Height or Width is 0");
205 }
206
3/5
✓ Branch 4 → 5 taken 61 times.
✓ Branch 4 → 9 taken 61 times.
✓ Branch 4 → 13 taken 61 times.
✗ Branch 4 → 17 not taken.
✗ Branch 4 → 21 not taken.
183 switch (plane) {
207 61 case PLANAR_Y:
208
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 61 times.
61 return (return_original) ? origPlanes[0] : fakePlanes[0];
209 61 case PLANAR_U:
210
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 61 times.
61 return (return_original) ? origPlanes[1] : fakePlanes[1];
211 61 case PLANAR_V:
212
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 61 times.
61 return (return_original) ? origPlanes[2] : fakePlanes[2];
213 case PLANAR_A:
214 return (return_original) ? origPlanes[3] : fakePlanes[3];
215 }
216 return origPlanes[0];
217 }
218
219 141 int GetPitchByIndex(int planeIndex) {
220
2/4
✓ Branch 2 → 3 taken 141 times.
✗ Branch 2 → 5 not taken.
✓ Branch 3 → 4 taken 141 times.
✗ Branch 3 → 5 not taken.
141 if (planeIndex>=0 && planeIndex <=3)
221 141 return pitches[planeIndex];
222 return pitches[0]; // Y
223 }
224
225
226 333 BYTE* GetPtrByIndex(int planeIndex) {
227
1/2
✓ Branch 2 → 3 taken 333 times.
✗ Branch 2 → 4 not taken.
333 if (!(_w && _h)) {
228 _RPT0(1,"Image444: Height or Width is 0");
229 }
230
2/4
✓ Branch 4 → 5 taken 333 times.
✗ Branch 4 → 10 not taken.
✓ Branch 5 → 6 taken 333 times.
✗ Branch 5 → 10 not taken.
333 if (planeIndex>=0 && planeIndex <=3)
231
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 333 times.
333 return (return_original) ? origPlanes[planeIndex] : fakePlanes[planeIndex];
232 return origPlanes[0]; // Y
233 }
234
235 /*
236 void SetPtr(BYTE* ptr, int plane) {
237 if (!(_w && _h)) {
238 _RPT0(1,"Image444: Height or Width is 0");
239 }
240 switch (plane) {
241 case PLANAR_Y:
242 fake_Y_plane = Y_plane = ptr;
243 break;
244 case PLANAR_U:
245 fake_Y_plane = U_plane = ptr;
246 break;
247 case PLANAR_V:
248 fake_Y_plane = V_plane = ptr;
249 break;
250 case PLANAR_A:
251 fake_A_plane = A_plane = ptr;
252 break;
253 }
254 }
255 */
256 void SetPtrByIndex(BYTE* ptr, int planeIndex) {
257 if (!(_w && _h)) {
258 _RPT0(1,"Image444: Height or Width is 0");
259 }
260 if (planeIndex >= 0 && planeIndex <= 3)
261 origPlanes[planeIndex] = fakePlanes[planeIndex] = ptr;
262 }
263
264
265 int GetPitch(int plane) {
266 if (!(_w && _h)) {
267 _RPT0(1,"Image444: Height or Width is 0");
268 }
269 switch (plane) {
270 case PLANAR_Y:
271 case PLANAR_G:
272 case PLANAR_B:
273 case PLANAR_R:
274 return pitch;
275 case PLANAR_U:
276 case PLANAR_V:
277 return pitchUV;
278 case PLANAR_A:
279 return pitchA;
280 }
281 return pitch;
282 }
283
284 62 void SubFrame(int x, int y, int new_w, int new_h) {
285 62 new_w = min(new_w, w()-x);
286 62 new_h = min(new_h, h()-y);
287
288 int pixelsize;
289
3/3
✓ Branch 6 → 7 taken 50 times.
✓ Branch 6 → 8 taken 8 times.
✓ Branch 6 → 9 taken 4 times.
62 switch(_bits_per_pixel) {
290 50 case 8: pixelsize = 1; break;
291 8 case 32: pixelsize = 4; break;
292 4 default: pixelsize = 2;
293 }
294
295
2/2
✓ Branch 13 → 11 taken 186 times.
✓ Branch 13 → 14 taken 62 times.
248 for (int p = 0; p < 3; p++)
296 {
297 186 fakePlanes[p] = GetPtrByIndex(p) + (x >> xSubSamplingShifts[p]) * pixelsize + (y >> ySubSamplingShifts[p]) * pitches[p];
298 }
299
2/2
✓ Branch 14 → 15 taken 6 times.
✓ Branch 14 → 17 taken 56 times.
62 fakePlanes[3] = pitches[3] > 0 ? (GetPtrByIndex(3) + (x >> xSubSamplingShifts[3])*pixelsize + (y >> ySubSamplingShifts[3])*pitches[3]) : nullptr;
300
301 62 fake_w = new_w;
302 62 fake_h = new_h;
303 62 fake_x_accum += x;
304 62 fake_y_accum += y;
305 62 }
306
307 // Accumulated luma x/y offset from all SubFrame calls since last ResetFake.
308 // Used by blend functions to compute the correct chroma column/row count via
309 // ceiling division when the starting position is not chroma-grid-aligned.
310
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 9 times.
9 int xAccum() const { return return_original ? 0 : fake_x_accum; }
311
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 6 times.
6 int yAccum() const { return return_original ? 0 : fake_y_accum; }
312
313 47 bool IsSizeZero() {
314
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 47 times.
47 if (w()<=0) return true;
315
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 47 times.
47 if (h()<=0) return true;
316
2/4
✓ Branch 8 → 9 taken 47 times.
✗ Branch 8 → 10 not taken.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 47 times.
47 if (!(pitch && origPlanes[0])) return true;
317 47 return false;
318 }
319
320 248 void ReturnOriginal(bool shouldI) {
321 248 return_original = shouldI;
322 248 }
323
324 233 void ResetFake() {
325 233 return_original = true;
326
2/2
✓ Branch 4 → 3 taken 932 times.
✓ Branch 4 → 5 taken 233 times.
1165 for (int i = 0; i < 4; i++)
327 932 fakePlanes[i] = origPlanes[i];
328 233 fake_w = _w;
329 233 fake_h = _h;
330 233 fake_x_accum = 0;
331 233 fake_y_accum = 0;
332 233 }
333
334 109 ~ImageOverlayInternal() {
335
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 109 times.
109 if(maskChroma)
336 Env->Free(maskChroma);
337 109 }
338
339 };
340
341
342 #endif
343