mbox series

[v3,0/4] visl: Adapt output frames for reference comparison

Message ID 20231123200451.148097-1-detlev.casanova@collabora.com
Headers show
Series visl: Adapt output frames for reference comparison | expand

Message

Detlev Casanova Nov. 23, 2023, 7:57 p.m. UTC
When using visl in automated tests, we need to have output frames that
can be compared to reference frames or hash of those to validate that
the whole pipeline is working properly.

Add a "stable_output" module parameter to make sure that a given input
stream always outputs the same frames.
This is done by skipping information like queues status and pointer
values.

This also adds some stable variation in the frames so that different
input give more different output.

Changes since v2:
 - Set parameters permissions to 0444 in visl and vidtv
 - Make stable_output true by default
 - Keep showing frames timestamps and remove vb2 buffer indexes only in
   stable output mode
 - Make codec_variablility non optional (remove parameter, keep
   implementation)
 - Add details on used variability fields
Changes since v1:
 - Fix typo in parameter documentation

Detlev Casanova (4):
  media: visl,vidtv: Set parameters permissions to 0444
  media: visl: Add a stable_output parameter
  doc: visl: Document stable_output parameter
  visl: Add codec specific variability on output frames

 Documentation/admin-guide/media/visl.rst      |   4 +
 .../media/test-drivers/vidtv/vidtv_bridge.c   |  20 +-
 drivers/media/test-drivers/visl/visl-core.c   |  15 +-
 drivers/media/test-drivers/visl/visl-dec.c    | 292 ++++++++++++------
 drivers/media/test-drivers/visl/visl.h        |   1 +
 5 files changed, 221 insertions(+), 111 deletions(-)

Comments

Hans Verkuil Dec. 6, 2023, 9:45 a.m. UTC | #1
On 23/11/2023 20:57, Detlev Casanova wrote:
> This avoids confusion with default values and lets userspace
> programs get the modules parameters values at run time.
> 
> This can be useful when setting up a test suite.

You missed a few more:

$ git grep "module_param.*, 0)" drivers/media/test-drivers/
drivers/media/test-drivers/vidtv/vidtv_bridge.c:module_param_array(vidtv_valid_dvb_t_freqs, uint, NULL, 0);
drivers/media/test-drivers/vidtv/vidtv_bridge.c:module_param_array(vidtv_valid_dvb_c_freqs, uint, NULL, 0);
drivers/media/test-drivers/vidtv/vidtv_bridge.c:module_param_array(vidtv_valid_dvb_s_freqs, uint, NULL, 0);

Regards,

	Hans

> 
> Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
> Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>
> ---
>  .../media/test-drivers/vidtv/vidtv_bridge.c   | 20 +++++++++----------
>  drivers/media/test-drivers/visl/visl-core.c   | 10 +++++-----
>  2 files changed, 15 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
> index 8b04e12af286..5dd7b1b4f7f1 100644
> --- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c
> +++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
> @@ -45,21 +45,21 @@
>  #define LNB_HIGH_FREQ		10600000	/* transition frequency */
>  
>  static unsigned int drop_tslock_prob_on_low_snr;
> -module_param(drop_tslock_prob_on_low_snr, uint, 0);
> +module_param(drop_tslock_prob_on_low_snr, uint, 0444);
>  MODULE_PARM_DESC(drop_tslock_prob_on_low_snr,
>  		 "Probability of losing the TS lock if the signal quality is bad");
>  
>  static unsigned int recover_tslock_prob_on_good_snr;
> -module_param(recover_tslock_prob_on_good_snr, uint, 0);
> +module_param(recover_tslock_prob_on_good_snr, uint, 0444);
>  MODULE_PARM_DESC(recover_tslock_prob_on_good_snr,
>  		 "Probability recovering the TS lock when the signal improves");
>  
>  static unsigned int mock_power_up_delay_msec;
> -module_param(mock_power_up_delay_msec, uint, 0);
> +module_param(mock_power_up_delay_msec, uint, 0444);
>  MODULE_PARM_DESC(mock_power_up_delay_msec, "Simulate a power up delay");
>  
>  static unsigned int mock_tune_delay_msec;
> -module_param(mock_tune_delay_msec, uint, 0);
> +module_param(mock_tune_delay_msec, uint, 0444);
>  MODULE_PARM_DESC(mock_tune_delay_msec, "Simulate a tune delay");
>  
>  static unsigned int vidtv_valid_dvb_t_freqs[NUM_VALID_TUNER_FREQS] = {
> @@ -86,7 +86,7 @@ MODULE_PARM_DESC(vidtv_valid_dvb_s_freqs,
>  		 "Valid DVB-S/S2 frequencies to simulate at Ku-Band, in kHz");
>  
>  static unsigned int max_frequency_shift_hz;
> -module_param(max_frequency_shift_hz, uint, 0);
> +module_param(max_frequency_shift_hz, uint, 0444);
>  MODULE_PARM_DESC(max_frequency_shift_hz,
>  		 "Maximum shift in HZ allowed when tuning in a channel");
>  
> @@ -96,24 +96,24 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums);
>   * Influences the signal acquisition time. See ISO/IEC 13818-1 : 2000. p. 113.
>   */
>  static unsigned int si_period_msec = 40;
> -module_param(si_period_msec, uint, 0);
> +module_param(si_period_msec, uint, 0444);
>  MODULE_PARM_DESC(si_period_msec, "How often to send SI packets. Default: 40ms");
>  
>  static unsigned int pcr_period_msec = 40;
> -module_param(pcr_period_msec, uint, 0);
> +module_param(pcr_period_msec, uint, 0444);
>  MODULE_PARM_DESC(pcr_period_msec,
>  		 "How often to send PCR packets. Default: 40ms");
>  
>  static unsigned int mux_rate_kbytes_sec = 4096;
> -module_param(mux_rate_kbytes_sec, uint, 0);
> +module_param(mux_rate_kbytes_sec, uint, 0444);
>  MODULE_PARM_DESC(mux_rate_kbytes_sec, "Mux rate: will pad stream if below");
>  
>  static unsigned int pcr_pid = 0x200;
> -module_param(pcr_pid, uint, 0);
> +module_param(pcr_pid, uint, 0444);
>  MODULE_PARM_DESC(pcr_pid, "PCR PID for all channels: defaults to 0x200");
>  
>  static unsigned int mux_buf_sz_pkts;
> -module_param(mux_buf_sz_pkts, uint, 0);
> +module_param(mux_buf_sz_pkts, uint, 0444);
>  MODULE_PARM_DESC(mux_buf_sz_pkts,
>  		 "Size for the internal mux buffer in multiples of 188 bytes");
>  
> diff --git a/drivers/media/test-drivers/visl/visl-core.c b/drivers/media/test-drivers/visl/visl-core.c
> index 9970dc739ca5..ef89eead6671 100644
> --- a/drivers/media/test-drivers/visl/visl-core.c
> +++ b/drivers/media/test-drivers/visl/visl-core.c
> @@ -64,27 +64,27 @@ MODULE_PARM_DESC(visl_transtime_ms, " simulated process time in milliseconds.");
>   * particular number of frames
>   */
>  int visl_dprintk_frame_start = -1;
> -module_param(visl_dprintk_frame_start, int, 0);
> +module_param(visl_dprintk_frame_start, int, 0444);
>  MODULE_PARM_DESC(visl_dprintk_frame_start,
>  		 " a frame number to start tracing with dprintk");
>  
>  unsigned int visl_dprintk_nframes;
> -module_param(visl_dprintk_nframes, uint, 0);
> +module_param(visl_dprintk_nframes, uint, 0444);
>  MODULE_PARM_DESC(visl_dprintk_nframes,
>  		 " the number of frames to trace with dprintk");
>  
>  bool keep_bitstream_buffers;
> -module_param(keep_bitstream_buffers, bool, false);
> +module_param(keep_bitstream_buffers, bool, 0444);
>  MODULE_PARM_DESC(keep_bitstream_buffers,
>  		 " keep bitstream buffers in debugfs after streaming is stopped");
>  
>  int bitstream_trace_frame_start = -1;
> -module_param(bitstream_trace_frame_start, int, 0);
> +module_param(bitstream_trace_frame_start, int, 0444);
>  MODULE_PARM_DESC(bitstream_trace_frame_start,
>  		 " a frame number to start dumping the bitstream through debugfs");
>  
>  unsigned int bitstream_trace_nframes;
> -module_param(bitstream_trace_nframes, uint, 0);
> +module_param(bitstream_trace_nframes, uint, 0444);
>  MODULE_PARM_DESC(bitstream_trace_nframes,
>  		 " the number of frames to dump the bitstream through debugfs");
>
Hans Verkuil Dec. 6, 2023, 10:46 a.m. UTC | #2
On 23/11/2023 20:57, Detlev Casanova wrote:
> This parameter is used to ensure that for a given input, the output
> frames are always identical so that it can be compared against
> a reference in automatic tests.
> 
> Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
> Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>
> ---
>  drivers/media/test-drivers/visl/visl-core.c |   5 +
>  drivers/media/test-drivers/visl/visl-dec.c  | 256 ++++++++++++--------
>  drivers/media/test-drivers/visl/visl.h      |   1 +
>  3 files changed, 166 insertions(+), 96 deletions(-)
> 
> diff --git a/drivers/media/test-drivers/visl/visl-core.c b/drivers/media/test-drivers/visl/visl-core.c
> index ef89eead6671..a9c060104932 100644
> --- a/drivers/media/test-drivers/visl/visl-core.c
> +++ b/drivers/media/test-drivers/visl/visl-core.c
> @@ -88,6 +88,11 @@ module_param(bitstream_trace_nframes, uint, 0444);
>  MODULE_PARM_DESC(bitstream_trace_nframes,
>  		 " the number of frames to dump the bitstream through debugfs");
>  
> +bool stable_output = true;
> +module_param(stable_output, bool, 0644);
> +MODULE_PARM_DESC(stable_output,
> +		 " only write stable data for a given input on the output frames");
> +

Seeing it like this I am still not happy with this.

So by default the data is stable (good!). But while disabling this option does
indeed make the data unstable, the real reason why you want to do that is to get
the addition information.

So this module name is just weird.

It is more a TPG info level that you provide here. Perhaps "tpg_verbose" is a better
name?

>  static const struct visl_ctrl_desc visl_fwht_ctrl_descs[] = {
>  	{
>  		.cfg.id = V4L2_CID_STATELESS_FWHT_PARAMS,
> diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
> index 318d675e5668..a6c878f0813a 100644
> --- a/drivers/media/test-drivers/visl/visl-dec.c
> +++ b/drivers/media/test-drivers/visl/visl-dec.c
> @@ -52,11 +52,17 @@ static void visl_get_ref_frames(struct visl_ctx *ctx, u8 *buf,
>  	case VISL_CODEC_FWHT: {
>  		struct vb2_buffer *vb2_buf;
>  
> -		vb2_buf = vb2_find_buffer(cap_q, run->fwht.params->backward_ref_ts);
> +		if (!stable_output) {

That will also change this condition to 'if (tpg_verbose)' which is better then
negating a boolean.

> +			vb2_buf = vb2_find_buffer(cap_q, run->fwht.params->backward_ref_ts);
> +
> +			scnprintf(buf, buflen, "backwards_ref_ts: %lld, vb2_idx: %d",
> +				  run->fwht.params->backward_ref_ts,
> +				  vb2_buf ? vb2_buf->index : -1);
> +		} else {
> +			scnprintf(buf, buflen, "backwards_ref_ts: %lld",
> +				  run->fwht.params->backward_ref_ts);
> +		}
>  
> -		scnprintf(buf, buflen, "backwards_ref_ts: %lld, vb2_idx: %d",
> -			  run->fwht.params->backward_ref_ts,
> -			  vb2_buf ? vb2_buf->index : -1);
>  		break;
>  	}
>  
> @@ -64,16 +70,25 @@ static void visl_get_ref_frames(struct visl_ctx *ctx, u8 *buf,
>  		struct vb2_buffer *b_ref;
>  		struct vb2_buffer *f_ref;
>  
> -		b_ref = vb2_find_buffer(cap_q, run->mpeg2.pic->backward_ref_ts);
> -		f_ref = vb2_find_buffer(cap_q, run->mpeg2.pic->forward_ref_ts);
> +		if (!stable_output) {
> +			b_ref = vb2_find_buffer(cap_q, run->mpeg2.pic->backward_ref_ts);
> +			f_ref = vb2_find_buffer(cap_q, run->mpeg2.pic->forward_ref_ts);
> +
> +			scnprintf(buf, buflen,
> +				  "backward_ref_ts: %llu, vb2_idx: %d\n"
> +				  "forward_ref_ts: %llu, vb2_idx: %d\n",
> +				  run->mpeg2.pic->backward_ref_ts,
> +				  b_ref ? b_ref->index : -1,
> +				  run->mpeg2.pic->forward_ref_ts,
> +				  f_ref ? f_ref->index : -1);
> +		} else {
> +			scnprintf(buf, buflen,
> +				  "backward_ref_ts: %llu\n"
> +				  "forward_ref_ts: %llu\n",
> +				  run->mpeg2.pic->backward_ref_ts,
> +				  run->mpeg2.pic->forward_ref_ts);
>  
> -		scnprintf(buf, buflen,
> -			  "backward_ref_ts: %llu, vb2_idx: %d\n"
> -			  "forward_ref_ts: %llu, vb2_idx: %d\n",
> -			  run->mpeg2.pic->backward_ref_ts,
> -			  b_ref ? b_ref->index : -1,
> -			  run->mpeg2.pic->forward_ref_ts,
> -			  f_ref ? f_ref->index : -1);
> +		}

I'm a bit unhappy about the amount of code churn here.

A lot of the time it prints a timestamp + buffer index. Perhaps a small
helper function will help:

		visl_print_ts_idx(&buf, &buflen, "backward_ref_ts", ts, b_ref);

That helper only prints the vb2_idx if enabled, and it can also omit it
if the vb2_buffer pointer == NULL.

>  		break;
>  	}
>  
> @@ -82,20 +97,30 @@ static void visl_get_ref_frames(struct visl_ctx *ctx, u8 *buf,
>  		struct vb2_buffer *golden;
>  		struct vb2_buffer *alt;
>  
> -		last = vb2_find_buffer(cap_q, run->vp8.frame->last_frame_ts);
> -		golden = vb2_find_buffer(cap_q, run->vp8.frame->golden_frame_ts);
> -		alt = vb2_find_buffer(cap_q, run->vp8.frame->alt_frame_ts);
> -
> -		scnprintf(buf, buflen,
> -			  "last_ref_ts: %llu, vb2_idx: %d\n"
> -			  "golden_ref_ts: %llu, vb2_idx: %d\n"
> -			  "alt_ref_ts: %llu, vb2_idx: %d\n",
> -			  run->vp8.frame->last_frame_ts,
> -			  last ? last->index : -1,
> -			  run->vp8.frame->golden_frame_ts,
> -			  golden ? golden->index : -1,
> -			  run->vp8.frame->alt_frame_ts,
> -			  alt ? alt->index : -1);
> +		if (!stable_output) {
> +			last = vb2_find_buffer(cap_q, run->vp8.frame->last_frame_ts);
> +			golden = vb2_find_buffer(cap_q, run->vp8.frame->golden_frame_ts);
> +			alt = vb2_find_buffer(cap_q, run->vp8.frame->alt_frame_ts);
> +
> +			scnprintf(buf, buflen,
> +				  "last_ref_ts: %llu, vb2_idx: %d\n"
> +				  "golden_ref_ts: %llu, vb2_idx: %d\n"
> +				  "alt_ref_ts: %llu, vb2_idx: %d\n",
> +				  run->vp8.frame->last_frame_ts,
> +				  last ? last->index : -1,
> +				  run->vp8.frame->golden_frame_ts,
> +				  golden ? golden->index : -1,
> +				  run->vp8.frame->alt_frame_ts,
> +				  alt ? alt->index : -1);
> +		} else {
> +			scnprintf(buf, buflen,
> +				  "last_ref_ts: %llu\n"
> +				  "golden_ref_ts: %llu\n"
> +				  "alt_ref_ts: %llu\n",
> +				  run->vp8.frame->last_frame_ts,
> +				  run->vp8.frame->golden_frame_ts,
> +				  run->vp8.frame->alt_frame_ts);
> +		}
>  		break;
>  	}
>  
> @@ -104,32 +129,49 @@ static void visl_get_ref_frames(struct visl_ctx *ctx, u8 *buf,
>  		struct vb2_buffer *golden;
>  		struct vb2_buffer *alt;
>  
> -		last = vb2_find_buffer(cap_q, run->vp9.frame->last_frame_ts);
> -		golden = vb2_find_buffer(cap_q, run->vp9.frame->golden_frame_ts);
> -		alt = vb2_find_buffer(cap_q, run->vp9.frame->alt_frame_ts);
> -
> -		scnprintf(buf, buflen,
> -			  "last_ref_ts: %llu, vb2_idx: %d\n"
> -			  "golden_ref_ts: %llu, vb2_idx: %d\n"
> -			  "alt_ref_ts: %llu, vb2_idx: %d\n",
> -			  run->vp9.frame->last_frame_ts,
> -			  last ? last->index : -1,
> -			  run->vp9.frame->golden_frame_ts,
> -			  golden ? golden->index : -1,
> -			  run->vp9.frame->alt_frame_ts,
> -			  alt ? alt->index : -1);
> +		if (!stable_output) {
> +			last = vb2_find_buffer(cap_q, run->vp9.frame->last_frame_ts);
> +			golden = vb2_find_buffer(cap_q, run->vp9.frame->golden_frame_ts);
> +			alt = vb2_find_buffer(cap_q, run->vp9.frame->alt_frame_ts);
> +
> +			scnprintf(buf, buflen,
> +				  "last_ref_ts: %llu, vb2_idx: %d\n"
> +				  "golden_ref_ts: %llu, vb2_idx: %d\n"
> +				  "alt_ref_ts: %llu, vb2_idx: %d\n",
> +				  run->vp9.frame->last_frame_ts,
> +				  last ? last->index : -1,
> +				  run->vp9.frame->golden_frame_ts,
> +				  golden ? golden->index : -1,
> +				  run->vp9.frame->alt_frame_ts,
> +				  alt ? alt->index : -1);
> +		} else {
> +			scnprintf(buf, buflen,
> +				  "last_ref_ts: %llu\n"
> +				  "golden_ref_ts: %llu\n"
> +				  "alt_ref_ts: %llu\n",
> +				  run->vp9.frame->last_frame_ts,
> +				  run->vp9.frame->golden_frame_ts,
> +				  run->vp9.frame->alt_frame_ts);
> +		}
>  		break;
>  	}
>  
>  	case VISL_CODEC_H264: {
>  		char entry[] = "dpb[%d]:%u, vb2_index: %d\n";
> +		char entry_stable[] = "dpb[%d]:%u\n";
>  		struct vb2_buffer *vb2_buf;
>  
>  		for (i = 0; i < ARRAY_SIZE(run->h264.dpram->dpb); i++) {
> -			vb2_buf = vb2_find_buffer(cap_q, run->h264.dpram->dpb[i].reference_ts);
> -			len = scnprintf(buf, buflen, entry, i,
> -					run->h264.dpram->dpb[i].reference_ts,
> -					vb2_buf ? vb2_buf->index : -1);
> +			if (!stable_output) {
> +				vb2_buf = vb2_find_buffer(cap_q,
> +							  run->h264.dpram->dpb[i].reference_ts);
> +				len = scnprintf(buf, buflen, entry, i,
> +						run->h264.dpram->dpb[i].reference_ts,
> +						vb2_buf ? vb2_buf->index : -1);
> +			} else {
> +				len = scnprintf(buf, buflen, entry_stable, i,
> +						run->h264.dpram->dpb[i].reference_ts);
> +			}
>  			buf += len;
>  			buflen -= len;
>  		}
> @@ -139,13 +181,20 @@ static void visl_get_ref_frames(struct visl_ctx *ctx, u8 *buf,
>  
>  	case VISL_CODEC_HEVC: {
>  		char entry[] = "dpb[%d]:%u, vb2_index: %d\n";
> +		char entry_stable[] = "dpb[%d]:%u\n";
>  		struct vb2_buffer *vb2_buf;
>  
>  		for (i = 0; i < ARRAY_SIZE(run->hevc.dpram->dpb); i++) {
> -			vb2_buf = vb2_find_buffer(cap_q, run->hevc.dpram->dpb[i].timestamp);
> -			len = scnprintf(buf, buflen, entry, i,
> -					run->hevc.dpram->dpb[i].timestamp,
> -					vb2_buf ? vb2_buf->index : -1);
> +			if (!stable_output) {
> +				vb2_buf = vb2_find_buffer(cap_q, run->hevc.dpram->dpb[i].timestamp);
> +				len = scnprintf(buf, buflen, entry, i,
> +						run->hevc.dpram->dpb[i].timestamp,
> +						vb2_buf ? vb2_buf->index : -1);
> +			} else {
> +				len = scnprintf(buf, buflen, entry_stable, i,
> +						run->hevc.dpram->dpb[i].timestamp);
> +			}
> +
>  			buf += len;
>  			buflen -= len;
>  		}
> @@ -197,19 +246,30 @@ static void visl_tpg_fill_sequence(struct visl_ctx *ctx,
>  {
>  	u32 stream_ms;
>  
> -	stream_ms = jiffies_to_msecs(get_jiffies_64() - ctx->capture_streamon_jiffies);
> -
> -	scnprintf(buf, bufsz,
> -		  "stream time: %02d:%02d:%02d:%03d sequence:%u timestamp:%lld field:%s",
> -		  (stream_ms / (60 * 60 * 1000)) % 24,
> -		  (stream_ms / (60 * 1000)) % 60,
> -		  (stream_ms / 1000) % 60,
> -		  stream_ms % 1000,
> -		  run->dst->sequence,
> -		  run->dst->vb2_buf.timestamp,
> -		  (run->dst->field == V4L2_FIELD_ALTERNATE) ?
> -		  (run->dst->field == V4L2_FIELD_TOP ?
> -		  " top" : " bottom") : "none");
> +	if (!stable_output) {
> +		stream_ms = jiffies_to_msecs(get_jiffies_64() - ctx->capture_streamon_jiffies);
> +
> +		scnprintf(buf, bufsz,
> +			  "stream time: %02d:%02d:%02d:%03d sequence:%u timestamp:%lld field:%s",
> +			  (stream_ms / (60 * 60 * 1000)) % 24,
> +			  (stream_ms / (60 * 1000)) % 60,
> +			  (stream_ms / 1000) % 60,
> +			  stream_ms % 1000,

The only difference here is the stream time, so just do that in a separate
scnprintf if tpg_verbose is set.

> +			  run->dst->sequence,
> +			  run->dst->vb2_buf.timestamp,
> +			  (run->dst->field == V4L2_FIELD_ALTERNATE) ?
> +			  (run->dst->field == V4L2_FIELD_TOP ?
> +			  " top" : " bottom") : "none");
> +	} else {
> +		scnprintf(buf, bufsz,
> +			  "sequence:%u timestamp:%lld field:%s",
> +			  run->dst->sequence,
> +			  run->dst->vb2_buf.timestamp,
> +			  (run->dst->field == V4L2_FIELD_ALTERNATE) ?
> +			  (run->dst->field == V4L2_FIELD_TOP ?
> +			  " top" : " bottom") : "none");
> +
> +	}
>  }
>  
>  static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
> @@ -280,28 +340,30 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>  		frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
>  	}
>  
> -	line++;
> -	frame_dprintk(ctx->dev, run->dst->sequence, "");
> -	scnprintf(buf, TPG_STR_BUF_SZ, "Output queue status:");
> -	tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
> -	frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
> +	if (!stable_output) {
> +		line++;
> +		frame_dprintk(ctx->dev, run->dst->sequence, "");
> +		scnprintf(buf, TPG_STR_BUF_SZ, "Output queue status:");
> +		tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
> +		frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
>  
> -	len = 0;
> -	for (i = 0; i < out_q->num_buffers; i++) {
> -		char entry[] = "index: %u, state: %s, request_fd: %d, ";
> -		u32 old_len = len;
> -		char *q_status = visl_get_vb2_state(out_q->bufs[i]->state);
> +		len = 0;
> +		for (i = 0; i < out_q->num_buffers; i++) {
> +			char entry[] = "index: %u, state: %s, request_fd: %d, ";
> +			u32 old_len = len;
> +			char *q_status = visl_get_vb2_state(out_q->bufs[i]->state);
>  
> -		len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
> -				 entry, i, q_status,
> -				 to_vb2_v4l2_buffer(out_q->bufs[i])->request_fd);
> +			len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
> +					 entry, i, q_status,
> +					 to_vb2_v4l2_buffer(out_q->bufs[i])->request_fd);
>  
> -		len += visl_fill_bytesused(to_vb2_v4l2_buffer(out_q->bufs[i]),
> -					   &buf[len],
> -					   TPG_STR_BUF_SZ - len);
> +			len += visl_fill_bytesused(to_vb2_v4l2_buffer(out_q->bufs[i]),
> +						   &buf[len],
> +						   TPG_STR_BUF_SZ - len);
>  
> -		tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
> -		frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);
> +			tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
> +			frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);
> +		}
>  	}
>  
>  	line++;
> @@ -333,25 +395,27 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>  		frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
>  	}
>  
> -	line++;
> -	frame_dprintk(ctx->dev, run->dst->sequence, "");
> -	scnprintf(buf, TPG_STR_BUF_SZ, "Capture queue status:");
> -	tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
> -	frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
> +	if (!stable_output) {
> +		line++;
> +		frame_dprintk(ctx->dev, run->dst->sequence, "");
> +		scnprintf(buf, TPG_STR_BUF_SZ, "Capture queue status:");
> +		tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
> +		frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
>  
> -	len = 0;
> -	for (i = 0; i < cap_q->num_buffers; i++) {
> -		u32 old_len = len;
> -		char *q_status = visl_get_vb2_state(cap_q->bufs[i]->state);
> +		len = 0;
> +		for (i = 0; i < cap_q->num_buffers; i++) {
> +			u32 old_len = len;
> +			char *q_status = visl_get_vb2_state(cap_q->bufs[i]->state);
>  
> -		len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
> -				 "index: %u, status: %s, timestamp: %llu, is_held: %d",
> -				 cap_q->bufs[i]->index, q_status,
> -				 cap_q->bufs[i]->timestamp,
> -				 to_vb2_v4l2_buffer(cap_q->bufs[i])->is_held);
> +			len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
> +					 "index: %u, status: %s, timestamp: %llu, is_held: %d",
> +					 cap_q->bufs[i]->index, q_status,
> +					 cap_q->bufs[i]->timestamp,
> +					 to_vb2_v4l2_buffer(cap_q->bufs[i])->is_held);
>  
> -		tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
> -		frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);
> +			tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
> +			frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);
> +		}
>  	}
>  }
>  
> diff --git a/drivers/media/test-drivers/visl/visl.h b/drivers/media/test-drivers/visl/visl.h
> index 31639f2e593d..5a81b493f121 100644
> --- a/drivers/media/test-drivers/visl/visl.h
> +++ b/drivers/media/test-drivers/visl/visl.h
> @@ -85,6 +85,7 @@ extern unsigned int visl_dprintk_nframes;
>  extern bool keep_bitstream_buffers;
>  extern int bitstream_trace_frame_start;
>  extern unsigned int bitstream_trace_nframes;
> +extern bool stable_output;
>  
>  #define frame_dprintk(dev, current, fmt, arg...) \
>  	do { \

Regards,

	Hans