66 * Merge to mainline testcard.
77 */
88/*
9- * Copyright (c) 2011-2024 CESNET
9+ * Copyright (c) 2011-2025 CESNET, zájmové sdružení právnických osob
1010 * All rights reserved.
1111 *
1212 * Redistribution and use in source and binary forms, with or without
9191#define BANNER_HEIGHT 150L
9292#define BANNER_MARGIN_BOTTOM 75L
9393#define BUFFER_SEC 1
94- #define DEFAULT_FORMAT "1920:1080:24:UYVY"
9594#define EPS_PLUS_1 1.0001
9695#define FONT_HEIGHT 108
96+ enum {
97+ NOISE_DEFAULT = 30 ,
98+ };
99+
100+ #define DEFAULT_FORMAT "1920:1080:24:UYVY"
97101#define MOD_NAME "[testcard2] "
98102
99103#ifdef HAVE_SDL3
@@ -109,6 +113,7 @@ struct testcard_state2 {
109113
110114 int count ;
111115 unsigned char * bg ; ///< bars converted to dest color_spec
116+ unsigned noise ; ///< add noise if >0; the magnitude is distance
112117 struct timeval t0 ;
113118 struct video_desc desc ;
114119 char * data ;
@@ -199,10 +204,13 @@ static int vidcap_testcard2_init(struct vidcap_params *params, void **state)
199204 color_printf ("testcard2 is an alternative implementation of testing signal source.\n" );
200205 color_printf ("It is less maintained than mainline testcard and has less features but has some extra ones, i. a. a timer (if SDL(2)_ttf is found.\n" );
201206 color_printf ("\n" );
202- color_printf ("testcard2 options :\n" );
207+ color_printf ("testcard2 usage :\n" );
203208 color_printf (TBOLD (TRED ("\t-t testcard2" ) "[:<width>:<height>:<fps>:<codec>]" ) "\n" );
204209 color_printf ("or\n" );
205210 color_printf (TBOLD (TRED ("\t-t testcard2" ) "[:size=<width>x<height>][:fps=<fps>][:codec=<codec>][:mode=<mode>]" ) "\n" );
211+ printf ("\nOptions:\n" );
212+ color_printf ("\t" TBOLD ("noise[=<val>]" ) " - add noise to the image\n" );
213+ printf ("\n" );
206214 testcard_show_codec_help ("testcard2" , true);
207215
208216 return VIDCAP_INIT_NOERR ;
@@ -260,6 +268,10 @@ static int vidcap_testcard2_init(struct vidcap_params *params, void **state)
260268 ret = false;
261269 break ;
262270 }
271+ } else if (IS_PREFIX (tmp , "noise" ) || IS_KEY_PREFIX (tmp , "noise" )) {
272+ s -> noise = IS_KEY_PREFIX (tmp , "noise" )
273+ ? atoi (strchr (tmp , '=' ) + 1 )
274+ : NOISE_DEFAULT ;
263275 } else {
264276 fprintf (stderr , "[testcard2] Unknown option: %s\n" , tmp );
265277 ret = false;
@@ -372,6 +384,22 @@ static void vidcap_testcard2_done(void *state)
372384 free (s );
373385}
374386
387+ static void
388+ add_noise (unsigned char * data , size_t len , unsigned bpp , unsigned noisiness )
389+ {
390+ if (noisiness == 0 ) {
391+ return ;
392+ }
393+ unsigned char * end = data + len ;
394+ data += bpp * (rand () % noisiness );
395+ while (data < end ) {
396+ for (unsigned i = 0 ; i < bpp ; ++ i ) {
397+ data [i ] = rand () % 256 ;
398+ }
399+ data += bpp * (1 + (rand () % noisiness ));
400+ }
401+ }
402+
375403/**
376404 * Only text banner is rendered in RGBA, other elements (background, squares) are already
377405 * converted to destination color space. Keep in mind that the regions should be aligned
@@ -506,6 +534,7 @@ void * vidcap_testcard2_thread(void *arg)
506534 d ++ ;
507535 }
508536 }
537+ add_noise (tmp , data_len , get_bpp (s -> desc .color_spec ), s -> noise );
509538 testcard_convert_buffer (RGBA , s -> desc .color_spec , tmp + (s -> desc .height - BANNER_MARGIN_BOTTOM - BANNER_HEIGHT ) * vc_get_linesize (s -> desc .width , s -> desc .color_spec ), (unsigned char * ) banner , s -> desc .width , BANNER_HEIGHT );
510539#ifdef HAVE_SDL3
511540 SDL_DestroySurface (text );
0 commit comments