GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 0.0% 0 / 0 / 12
Functions: 0.0% 0 / 0 / 6
Branches: 0.0% 0 / 0 / 12

filters/text-overlay.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 #ifndef __Text_overlay_H__
36 #define __Text_overlay_H__
37
38 #include <avisynth.h>
39
40 #ifdef AVS_WINDOWS
41 #include <avs/win.h>
42 #else
43 #include <avs/posix.h>
44 #endif
45
46 #include <cstdio>
47 #include <stdint.h>
48 #include <string>
49 #include <vector>
50 #include "../core/info.h"
51
52
53 /********************************************************************
54 ********************************************************************/
55
56
57 #if defined(AVS_WINDOWS) && !defined(NO_WIN_GDI)
58 #include "overlay/blend_common.h" // MaskMode, PLACEMENT_*
59 #include <vector>
60 #include "getalpharect_impl.h"
61
62 /*
63 * Antialiaser — GDI-based anti-aliased text renderer for AviSynth+ video frames.
64 *
65 * OVERVIEW
66 * --------
67 * The caller draws text into an internal 8x-supersampled 1-bit GDI DIB via GetDC().
68 * Apply() then composites that text onto the video frame by:
69 * 1. GetAlphaRect() — scans the DIB, gamma-corrects, and computes per-pixel
70 * blend weights (basealpha) and pre-scaled color addends (Y/R, U/G, V/B),
71 * all as uint16_t values stored in soa_buf.
72 * 2. ApplyPlanar_SoA / ApplyYUY2 / ApplyRGB_packed — reads from soa_buf and
73 * blends those values onto the actual video pixels.
74 *
75 * FORMAT-AGNOSTIC MASK BUFFER
76 * ---------------------------
77 * soa_buf is always uint16_t, regardless of the video format (8-bit, 10–16-bit
78 * integer, or 32-bit float). GetAlphaRect() produces:
79 * basealpha : 0..256 (256 = fully transparent — pixel untouched)
80 * Y/R, U/G, V/B addends : 0..~65530
81 * These are fixed-point values scaled to 8-bit headroom. The Apply functions
82 * rescale on the fly: integer formats left-shift the addend by (bpp-8), float
83 * formats divide by 65536. The mask computation itself never needs to know the
84 * output bit depth.
85 *
86 * CHROMA PLACEMENT SUPPORT
87 * ------------------------
88 * For subsampled YUV formats the U/G and V/B planes in soa_buf are stored at
89 * full luma resolution. When Apply() composites a subsampled clip, each UV
90 * output pixel is derived by spatially downsampling the corresponding luma-
91 * resolution mask row(s) using prepare_effective_mask_for_row<MaskMode,...>
92 * (from overlay/blend_common.h). The MaskMode encodes both the subsampling
93 * ratio (4:4:4, 4:2:2, 4:2:0, 4:1:1) and the chroma siting (CENTER (MPEG1) / LEFT (MPEG2) /
94 * TOP_LEFT), giving correct chroma placement rather than a naive box average.
95 *
96 * Eight MaskModes cover all supported combinations. rowprep_fns[8] holds one
97 * function pointer per MaskMode, with the best available SIMD tier (AVX2 /
98 * SSE4.1 / scalar) selected once at construction time from cpuFlags. Apply()
99 * computes the actual MaskMode at call time from the VideoInfo subsampling
100 * factors and the stored chromaplacement member, so the same Antialiaser
101 * instance can be reused if the clip format ever changes.
102 *
103 * BUFFER LAYOUT (row-interleaved SoA)
104 * -------------------------------------
105 * The original implementation stored the four mask components interleaved per
106 * pixel (AoS: [ba,bv,gu,ry] packed as four consecutive uint16_t). That layout
107 * is ideal for GetAlphaRect() writes (one sequential stream) but stride-4 for
108 * the Apply readers.
109 *
110 * The current layout is row-interleaved SoA: within each scanline the four
111 * sub-planes are stored consecutively, each w_stride elements wide:
112 *
113 * row y: [ ba_0..ba_n | ry_0..ry_n | u_0..u_n | v_0..v_n ]
114 * plane 0 plane 1 plane 2 plane 3
115 *
116 * row y, plane p: soa_buf + y * 4 * w_stride + p * w_stride
117 *
118 * w_stride = (w + 31) & ~31, rounding up to a multiple of 32 so every sub-row
119 * starts on a 64-byte cache-line boundary.
120 *
121 * This is a compromise between the two extremes:
122 * - Full AoS (old): GetAlphaRect() writes one stream (optimal), Apply reads
123 * with stride 4 (poor locality per plane).
124 * - Full SoA (four separate plane allocations): Apply reads are stride-1
125 * (optimal per plane), but GetAlphaRect() writes to four streams that are
126 * w*h*2 bytes apart (~600 KB for 640×480), causing heavy cache thrashing.
127 * - Row-interleaved SoA (current): GetAlphaRect() writes four streams that
128 * are at most w_stride*2 bytes apart (<=1280 bytes for 640-wide), all within
129 * one L1-cache-sized window per row. Apply reads each plane stride-1 within
130 * a row and steps by 4*w_stride between rows — well within prefetcher range.
131 *
132 * Overall throughput is broadly on par with the original AoS method while
133 * enabling correct chroma-placement-aware UV compositing.
134 */
135 class Antialiaser
136 {
137 public:
138 Antialiaser(int width, int height, const char fontname[], int size,
139 int textcolor, int halocolor, bool _bold, bool _italic, bool _noaa,
140 int64_t cpuFlags,
141 int chromaplacement,
142 int font_width=0, int font_angle=0, bool _interlaced=false);
143 virtual ~Antialiaser();
144 HDC GetDC();
145 void FreeDC();
146
147 void Apply(const VideoInfo& vi, PVideoFrame* frame, int pitch);
148
149 private:
150 template<MaskMode maskMode, int bits_per_pixel>
151 void ApplyPlanar_SoA(BYTE* buf, int pitch, int pitchUV, BYTE* bufU, BYTE* bufV, bool isRGB);
152 void ApplyYUY2(BYTE* buf, int pitch);
153
154 template<typename pixel_t, bool has_alpha>
155 void ApplyRGB_packed(BYTE* buf, int pitch);
156
157 using rowprep_u16_fn_t = const uint16_t*(*)(const uint16_t*, int, int, std::vector<uint16_t>&, int, int, MagicDiv);
158
159 void* lpAntialiasBits;
160 // Row-interleaved SoA: each scanline holds [ba|ry|u|v], each sub-row w_stride wide.
161 // Row y, plane p: soa_buf + y * 4 * w_stride + p * w_stride
162 // w_stride = (w + 31) & ~31 — rounded up so each sub-row is 64-byte aligned.
163 uint16_t* soa_buf; // single allocation: w_stride * h * 4 uint16_t
164 int w_stride; // padded row stride (>= w, multiple of 32)
165 std::vector<uint16_t> uv_buf_ba, uv_buf_u, uv_buf_v; // scratch for ApplyPlanar_SoA UV section, sized w
166 rowprep_u16_fn_t rowprep_fns[8]; // one per MaskMode, SIMD variant selected at construction
167 int chromaplacement; // PLACEMENT_MPEG1/MPEG2/TOPLEFT — used in Apply() per-call
168 HDC hdcAntialias;
169 HBITMAP hbmAntialias;
170 HFONT hfontDefault;
171 HBITMAP hbmDefault;
172 const int w, h;
173 const int textcolor, halocolor;
174 int xl, yt, xr, yb; // sub-rectangle containing live text
175 bool dirty, interlaced;
176 bool bold, italic;
177 bool noaa;
178
179 #ifdef INTEL_INTRINSICS
180 getalpharect_fn_t getalpharect_fn;
181 #endif
182 void GetAlphaRect();
183 };
184 #endif
185
186
187 class ShowFrameNumber : public GenericVideoFilter
188 /**
189 * Class to display frame number on a video clip
190 **/
191 {
192 public:
193 ShowFrameNumber(PClip _child, bool _scroll, int _offset, int _x, int _y, const char _fontname[], int _size,
194 int _textcolor, int _halocolor, int font_width, int font_angle, bool _bold, bool _italic, bool _noaa, bool _gdi, IScriptEnvironment* env);
195 PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) override;
196
197 static AVSValue __cdecl Create(AVSValue args, void*, IScriptEnvironment* env);
198
199 int __stdcall SetCacheHints(int cachehints, int frame_range) override {
200 AVS_UNUSED(frame_range);
201 return cachehints == CACHE_GET_MTMODE ? MT_MULTI_INSTANCE : 0;
202 // Antialiaser usage -> MT_MULTI_INSTANCE (with NICE_FILTER rect area conflicts)
203 }
204
205 private:
206 const bool use_gdi;
207 #if defined(AVS_WINDOWS) && !defined(NO_WIN_GDI)
208 std::unique_ptr<Antialiaser> antialiaser;
209 #endif
210 std::unique_ptr<BitmapFont> current_font;
211 int chromaplacement;
212 const bool scroll;
213 const int offset;
214 const int size, x, y;
215 const int textcolor, halocolor;
216 [[maybe_unused]] const bool bold;
217 [[maybe_unused]] const bool italic; // n/a in NO_WIN_GDI
218 [[maybe_unused]] const bool noaa; // n/a in NO_WIN_GDI
219 };
220
221 class ShowCRC32 : public GenericVideoFilter
222 /**
223 * Class to display CRC32 checksum of selected planes on a video clip
224 **/
225 {
226 uint32_t crc32_table[256];
227
228 void build_crc32_table(void);
229 std::string compute_crc_text(PVideoFrame& crc_frame, std::vector<uint32_t>& out_values) const;
230
231 public:
232 ShowCRC32(PClip _child, PClip _crc_child, bool _scroll, int _offset, int _x, int _y,
233 const char _fontname[], int _size,
234 int _textcolor, int _halocolor, int font_width, int font_angle,
235 bool _bold, bool _italic, bool _noaa, bool _gdi,
236 const char* channels, int _mode, bool _compatible_mode, int _showmode, IScriptEnvironment* env);
237 PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) override;
238
239 static AVSValue __cdecl Create(AVSValue args, void*, IScriptEnvironment* env);
240
241 int __stdcall SetCacheHints(int cachehints, int frame_range) override {
242 AVS_UNUSED(frame_range);
243 return cachehints == CACHE_GET_MTMODE ? MT_MULTI_INSTANCE : 0;
244 }
245
246 private:
247 PClip crc_child;
248 bool doY, doU, doV, doR, doG, doB, doA;
249 const int mode;
250 bool compatible_mode;
251 const int showmode;
252 const bool use_gdi;
253 #if defined(AVS_WINDOWS) && !defined(NO_WIN_GDI)
254 std::unique_ptr<Antialiaser> antialiaser;
255 #endif
256 std::unique_ptr<BitmapFont> current_font;
257 int chromaplacement;
258 const bool scroll;
259 const int offset;
260 const int size, x, y;
261 const int textcolor, halocolor;
262 [[maybe_unused]] const bool bold;
263 [[maybe_unused]] const bool italic; // n/a in NO_WIN_GDI
264 [[maybe_unused]] const bool noaa; // n/a in NO_WIN_GDI
265 };
266
267
268
269 class ShowSMPTE : public GenericVideoFilter
270 /**
271 * Class to display SMPTE codes on a video clip
272 **/
273 {
274 public:
275 ShowSMPTE(PClip _child, double _rate, const char* _offset, int _offset_f, int _x, int _y, const char _fontname[], int _size,
276 int _textcolor, int _halocolor, int font_width, int font_angle, bool _bold, bool _italic, bool _noaa, bool _gdi, IScriptEnvironment* env);
277 PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) override;
278
279 static AVSValue __cdecl CreateSMTPE(AVSValue args, void*, IScriptEnvironment* env);
280 static AVSValue __cdecl CreateTime(AVSValue args, void*, IScriptEnvironment* env);
281
282 int __stdcall SetCacheHints(int cachehints, int frame_range) override {
283 AVS_UNUSED(frame_range);
284 return cachehints == CACHE_GET_MTMODE ? MT_MULTI_INSTANCE : 0;
285 // Antialiaser usage -> MT_MULTI_INSTANCE (with NICE_FILTER rect area conflicts)
286 }
287
288 private:
289 const bool use_gdi;
290 #if defined(AVS_WINDOWS) && !defined(NO_WIN_GDI)
291 std::unique_ptr<Antialiaser> antialiaser;
292 #endif
293 std::unique_ptr<BitmapFont> current_font;
294 int chromaplacement;
295 int rate;
296 int offset_f;
297 const int x, y;
298 bool dropframe;
299 const int textcolor, halocolor;
300 [[maybe_unused]] const bool bold;
301 [[maybe_unused]] const bool italic; // n/a in NO_WIN_GDI
302 [[maybe_unused]] const bool noaa; // n/a in NO_WIN_GDI
303 };
304
305
306
307 #if defined(AVS_WINDOWS) && !defined(NO_WIN_GDI)
308 class Subtitle : public GenericVideoFilter
309 /**
310 * Subtitle creation class
311 **/
312 {
313 public:
314 Subtitle( PClip _child, const char _text[], int _x, int _y, int _firstframe, int _lastframe,
315 const char _fontname[], int _size, int _textcolor, int _halocolor, int _align,
316 int _spc, bool _multiline, int _lsp, int _font_width, int _font_angle, bool _interlaced, const char _font_filename[], const bool _utf8,
317 const bool _bold, const bool _italic, const bool _noaa, int _chromaplacement, IScriptEnvironment* env);
318 virtual ~Subtitle(void);
319 PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) override;
320
321 static AVSValue __cdecl Create(AVSValue args, void*, IScriptEnvironment* env);
322
323 int __stdcall SetCacheHints(int cachehints, int frame_range) override {
324 AVS_UNUSED(frame_range);
325 return cachehints == CACHE_GET_MTMODE ? MT_MULTI_INSTANCE : 0;
326 // Antialiaser usage -> MT_MULTI_INSTANCE (with NICE_FILTER rect area conflicts)
327 }
328
329 private:
330 void InitAntialiaser(IScriptEnvironment* env);
331
332 const int x, y, firstframe, lastframe, size, lsp, font_width, font_angle;
333 const bool multiline, interlaced;
334 const int textcolor, halocolor, align, spc;
335 const char* const fontname;
336 const char* const text;
337 const char* const font_filename;
338 const bool utf8;
339 const bool bold;
340 const bool italic;
341 const bool noaa;
342 const int chromaplacement;
343 Antialiaser* antialiaser;
344 };
345 #endif
346
347 class SimpleText : public GenericVideoFilter
348 /**
349 * SimpleText creation class
350 **/
351 {
352 public:
353 SimpleText(PClip _child, const char _text[], int _x, int _y, int _firstframe, int _lastframe,
354 const char _fontname[], int _size, int _textcolor, int _halocolor, int _align,
355 int _spc, bool _multiline, int _lsp, int _font_width, int _font_angle, bool _interlaced, const char _font_filename[],
356 const bool _utf8, const bool _bold, const int _chromalocation,
357 IScriptEnvironment* env);
358 virtual ~SimpleText(void);
359 PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) override;
360
361 static AVSValue __cdecl Create(AVSValue args, void*, IScriptEnvironment* env);
362
363 int __stdcall SetCacheHints(int cachehints, int frame_range) override {
364 AVS_UNUSED(frame_range);
365 return cachehints == CACHE_GET_MTMODE ? MT_NICE_FILTER : 0;
366 }
367
368 private:
369 const int x, y, firstframe, lastframe;
370 const int size;
371 const int lsp;
372 // const int font_width, font_angle; // n/a
373 const bool multiline;
374 // const bool interlaced; // n/a
375 const int textcolor, halocolor, align;
376 // const int spc; // n/a
377 const int halocolor_orig;
378 const char* const fontname; // Terminus or info_h
379 const char* const text;
380 const char* const font_filename; // .BDF files
381 const bool utf8;
382 const bool bold;
383 const int chromalocation;
384 std::unique_ptr<BitmapFont> current_font;
385 };
386
387 class FilterInfo : public GenericVideoFilter
388 /**
389 * FilterInfo creation class
390 **/
391 {
392 public:
393 FilterInfo( PClip _child, const char _fontname[], int _size, int _textcolor, int _halocolor, bool _bold, bool _italic, bool _noaa, bool _cpu, int _x, int _y, int _align, bool _gdi, IScriptEnvironment* env);
394 virtual ~FilterInfo(void);
395 PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) override;
396 bool __stdcall GetParity(int n) override;
397
398 static AVSValue __cdecl Create(AVSValue args, void*, IScriptEnvironment* env);
399
400 int __stdcall SetCacheHints(int cachehints, int frame_range) override {
401 AVS_UNUSED(frame_range);
402 return cachehints == CACHE_GET_MTMODE ? MT_MULTI_INSTANCE : 0;
403 // Antialiaser usage -> MT_MULTI_INSTANCE (with NICE_FILTER rect area conflicts)
404 }
405
406 private:
407 const VideoInfo& AdjustVi();
408
409 const VideoInfo &vii;
410
411 const int size;
412
413 const int text_color, halo_color;
414 const bool use_gdi;
415 #if defined(AVS_WINDOWS) && !defined(NO_WIN_GDI)
416 std::unique_ptr<Antialiaser> antialiaser;
417 #endif
418 std::unique_ptr<BitmapFont> current_font;
419 int chromaplacement;
420 [[maybe_unused]] const bool bold;
421 [[maybe_unused]] const bool italic;
422 [[maybe_unused]] const bool noaa;
423 const bool cpu;
424 const int x, y;
425 const int align;
426 };
427
428
429 class Compare : public GenericVideoFilter
430 /**
431 * Compare two clips frame by frame and display fidelity measurements (with optionnal logging to file)
432 **/
433 {
434 public:
435 Compare(PClip _child1, PClip _child2, const char* channels, const char *fname, bool _show_graph, bool _gdi, IScriptEnvironment* env);
436 ~Compare();
437 static AVSValue __cdecl Create(AVSValue args, void* , IScriptEnvironment* env);
438 PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) override;
439
440 int __stdcall SetCacheHints(int cachehints, int frame_range) override {
441 AVS_UNUSED(frame_range);
442 return cachehints == CACHE_GET_MTMODE ? MT_SERIALIZED : 0;
443 // Antialiaser usage -> MT_MULTI_INSTANCE (with NICE_FILTER rect area conflicts)
444 // show_graph gathers data of last n frames inside class -> conditional MT_SERIALIZED
445 // logfile writing: if log -> conditional MT_SERIALIZED
446 // display of global counters -> MT_SERIALIZED
447 // So least common multiple -> MT_SERIALIZED
448 }
449
450
451 private:
452 bool use_gdi;
453 #if defined(AVS_WINDOWS) && !defined(NO_WIN_GDI)
454 std::unique_ptr<Antialiaser> antialiaser;
455 #endif
456 std::unique_ptr<BitmapFont> current_font;
457 int chromaplacement;
458 PClip child2;
459 uint32_t mask;
460 uint64_t mask64;
461 int masked_bytes;
462 FILE* log;
463 int* psnrs;
464 bool show_graph;
465 double PSNR_min, PSNR_tot, PSNR_max;
466 double MAD_min, MAD_tot, MAD_max;
467 double MD_min, MD_tot, MD_max;
468 double bytecount_overall, SSD_overall;
469 int framecount;
470 int planar_plane;
471 int pixelsize;
472 int bits_per_pixel;
473 const int text_color, halo_color;
474
475 };
476
477
478
479 /**** Helper functions ****/
480
481 void ApplyMessage( PVideoFrame* frame, const VideoInfo& vi, const char* message, int size,
482 int textcolor, int halocolor, int bgcolor, IScriptEnvironment* env );
483
484 bool GetTextBoundingBox( const char* text, const char* fontname, int size, bool bold,
485 bool italic, int align, int* width, int* height );
486
487 bool GetTextBoundingBoxFixed(const char* text, const char* fontname, int size, bool bold,
488 bool italic, int align, int& width, int& height, bool utf8);
489
490 #endif // __Text_overlay_H__
491