root/drivers/media/test-drivers/visl/visl-dec.c
// SPDX-License-Identifier: GPL-2.0
/*
 * Contains the virtual decoder logic. The functions here control the
 * tracing/TPG on a per-frame basis
 */

#include "visl.h"
#include "visl-debugfs.h"
#include "visl-dec.h"
#include "visl-trace-fwht.h"
#include "visl-trace-mpeg2.h"
#include "visl-trace-vp8.h"
#include "visl-trace-vp9.h"
#include "visl-trace-h264.h"
#include "visl-trace-hevc.h"
#include "visl-trace-av1.h"

#include <linux/delay.h>
#include <linux/workqueue.h>
#include <media/v4l2-mem2mem.h>
#include <media/tpg/v4l2-tpg.h>

#define LAST_BUF_IDX (V4L2_AV1_REF_LAST_FRAME - V4L2_AV1_REF_LAST_FRAME)
#define LAST2_BUF_IDX (V4L2_AV1_REF_LAST2_FRAME - V4L2_AV1_REF_LAST_FRAME)
#define LAST3_BUF_IDX (V4L2_AV1_REF_LAST3_FRAME - V4L2_AV1_REF_LAST_FRAME)
#define GOLDEN_BUF_IDX (V4L2_AV1_REF_GOLDEN_FRAME - V4L2_AV1_REF_LAST_FRAME)
#define BWD_BUF_IDX (V4L2_AV1_REF_BWDREF_FRAME - V4L2_AV1_REF_LAST_FRAME)
#define ALT2_BUF_IDX (V4L2_AV1_REF_ALTREF2_FRAME - V4L2_AV1_REF_LAST_FRAME)
#define ALT_BUF_IDX (V4L2_AV1_REF_ALTREF_FRAME - V4L2_AV1_REF_LAST_FRAME)

static void *plane_vaddr(struct tpg_data *tpg, struct vb2_buffer *buf,
                         u32 p, u32 bpl[TPG_MAX_PLANES], u32 h)
{
        u32 i;
        void *vbuf;

        if (p == 0 || tpg_g_buffers(tpg) > 1)
                return vb2_plane_vaddr(buf, p);
        vbuf = vb2_plane_vaddr(buf, 0);
        for (i = 0; i < p; i++)
                vbuf += bpl[i] * h / tpg->vdownsampling[i];
        return vbuf;
}

static void visl_print_ts_idx(u8 **buf, __kernel_size_t *buflen, const char *name,
                              u64 ts, struct vb2_buffer *vb2_buf)
{
        u32 len;

        if (tpg_verbose && vb2_buf) {
                len = scnprintf(*buf, *buflen, "%s: %lld, vb2_idx: %d\n", name,
                                ts, vb2_buf->index);
        } else {
                len = scnprintf(*buf, *buflen, "%s: %lld\n", name, ts);
        }

        *buf += len;
        *buflen -= len;
}

static void visl_get_ref_frames(struct visl_ctx *ctx, u8 *buf,
                                __kernel_size_t buflen, struct visl_run *run)
{
        struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
        char header[] = "Reference frames:\n";
        u32 i;
        u32 len;

        len = scnprintf(buf, buflen, header);
        buf += len;
        buflen -= len;

        switch (ctx->current_codec) {
        case VISL_CODEC_NONE:
                break;

        case VISL_CODEC_FWHT: {
                struct vb2_buffer *vb2_buf;

                vb2_buf = vb2_find_buffer(cap_q, run->fwht.params->backward_ref_ts);

                visl_print_ts_idx(&buf, &buflen, "backwards_ref_ts",
                                  run->fwht.params->backward_ref_ts, vb2_buf);

                break;
        }

        case VISL_CODEC_MPEG2: {
                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);

                visl_print_ts_idx(&buf, &buflen, "backward_ref_ts",
                                  run->mpeg2.pic->backward_ref_ts, b_ref);
                visl_print_ts_idx(&buf, &buflen, "forward_ref_ts",
                                  run->mpeg2.pic->forward_ref_ts, f_ref);

                break;
        }

        case VISL_CODEC_VP8: {
                struct vb2_buffer *last;
                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);

                visl_print_ts_idx(&buf, &buflen, "last_ref_ts",
                                  run->vp8.frame->last_frame_ts, last);
                visl_print_ts_idx(&buf, &buflen, "golden_ref_ts",
                                  run->vp8.frame->golden_frame_ts, golden);
                visl_print_ts_idx(&buf, &buflen, "alt_ref_ts",
                                  run->vp8.frame->alt_frame_ts, alt);

                break;
        }

        case VISL_CODEC_VP9: {
                struct vb2_buffer *last;
                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);

                visl_print_ts_idx(&buf, &buflen, "last_ref_ts",
                                  run->vp9.frame->last_frame_ts, last);
                visl_print_ts_idx(&buf, &buflen, "golden_ref_ts",
                                  run->vp9.frame->golden_frame_ts, golden);
                visl_print_ts_idx(&buf, &buflen, "alt_ref_ts",
                                  run->vp9.frame->alt_frame_ts, alt);

                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);
                        if (tpg_verbose && vb2_buf) {
                                len = scnprintf(buf, buflen, entry, i,
                                                run->h264.dpram->dpb[i].reference_ts,
                                                vb2_buf->index);
                        } else {
                                len = scnprintf(buf, buflen, entry_stable, i,
                                                run->h264.dpram->dpb[i].reference_ts);
                        }
                        buf += len;
                        buflen -= len;
                }

                break;
        }

        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);
                        if (tpg_verbose && vb2_buf) {
                                len = scnprintf(buf, buflen, entry, i,
                                                run->hevc.dpram->dpb[i].timestamp,
                                                vb2_buf->index);
                        } else {
                                len = scnprintf(buf, buflen, entry_stable, i,
                                                run->hevc.dpram->dpb[i].timestamp);
                        }

                        buf += len;
                        buflen -= len;
                }

                break;
        }

        case VISL_CODEC_AV1: {
                int idx_last = run->av1.frame->ref_frame_idx[LAST_BUF_IDX];
                int idx_last2 = run->av1.frame->ref_frame_idx[LAST2_BUF_IDX];
                int idx_last3 = run->av1.frame->ref_frame_idx[LAST3_BUF_IDX];
                int idx_golden = run->av1.frame->ref_frame_idx[GOLDEN_BUF_IDX];
                int idx_bwd = run->av1.frame->ref_frame_idx[BWD_BUF_IDX];
                int idx_alt2 = run->av1.frame->ref_frame_idx[ALT2_BUF_IDX];
                int idx_alt = run->av1.frame->ref_frame_idx[ALT_BUF_IDX];

                const u64 *reference_frame_ts = run->av1.frame->reference_frame_ts;

                struct vb2_buffer *ref_last =
                        vb2_find_buffer(cap_q, reference_frame_ts[idx_last]);
                struct vb2_buffer *ref_last2 =
                        vb2_find_buffer(cap_q, reference_frame_ts[idx_last2]);
                struct vb2_buffer *ref_last3 =
                        vb2_find_buffer(cap_q, reference_frame_ts[idx_last3]);
                struct vb2_buffer *ref_golden =
                        vb2_find_buffer(cap_q, reference_frame_ts[idx_golden]);
                struct vb2_buffer *ref_bwd =
                        vb2_find_buffer(cap_q, reference_frame_ts[idx_bwd]);
                struct vb2_buffer *ref_alt2 =
                        vb2_find_buffer(cap_q, reference_frame_ts[idx_alt2]);
                struct vb2_buffer *ref_alt =
                        vb2_find_buffer(cap_q, reference_frame_ts[idx_alt]);

                visl_print_ts_idx(&buf, &buflen, "ref_last_ts",
                                  reference_frame_ts[idx_last], ref_last);
                visl_print_ts_idx(&buf, &buflen, "ref_last2_ts",
                                  reference_frame_ts[idx_last2], ref_last2);
                visl_print_ts_idx(&buf, &buflen, "ref_last3_ts",
                                  reference_frame_ts[idx_last3], ref_last3);
                visl_print_ts_idx(&buf, &buflen, "ref_golden_ts",
                                  reference_frame_ts[idx_golden], ref_golden);
                visl_print_ts_idx(&buf, &buflen, "ref_bwd_ts",
                                  reference_frame_ts[idx_bwd], ref_bwd);
                visl_print_ts_idx(&buf, &buflen, "ref_alt2_ts",
                                  reference_frame_ts[idx_alt2], ref_alt2);
                visl_print_ts_idx(&buf, &buflen, "ref_alt_ts",
                                  reference_frame_ts[idx_alt], ref_alt);

                break;
        }
        }
}

static char *visl_get_vb2_state(enum vb2_buffer_state state)
{
        switch (state) {
        case VB2_BUF_STATE_DEQUEUED:
                return "Dequeued";
        case VB2_BUF_STATE_IN_REQUEST:
                return "In request";
        case VB2_BUF_STATE_PREPARING:
                return "Preparing";
        case VB2_BUF_STATE_QUEUED:
                return "Queued";
        case VB2_BUF_STATE_ACTIVE:
                return "Active";
        case VB2_BUF_STATE_DONE:
                return "Done";
        case VB2_BUF_STATE_ERROR:
                return "Error";
        default:
                return "";
        }
}

static int visl_fill_bytesused(struct vb2_v4l2_buffer *v4l2_vb2_buf, char *buf, size_t bufsz)
{
        int len = 0;
        u32 i;

        for (i = 0; i < v4l2_vb2_buf->vb2_buf.num_planes; i++)
                len += scnprintf(buf, bufsz,
                                "bytesused[%u]: %u length[%u]: %u data_offset[%u]: %u",
                                i, v4l2_vb2_buf->planes[i].bytesused,
                                i, v4l2_vb2_buf->planes[i].length,
                                i, v4l2_vb2_buf->planes[i].data_offset);

        return len;
}

static void visl_tpg_fill_sequence(struct visl_ctx *ctx,
                                   struct visl_run *run, char buf[], size_t bufsz)
{
        u32 stream_ms;
        int len;

        if (tpg_verbose) {
                stream_ms = jiffies_to_msecs(get_jiffies_64() - ctx->capture_streamon_jiffies);

                len = scnprintf(buf, bufsz,
                                "stream time: %02d:%02d:%02d:%03d ",
                                (stream_ms / (60 * 60 * 1000)) % 24,
                                (stream_ms / (60 * 1000)) % 60,
                                (stream_ms / 1000) % 60,
                                stream_ms % 1000);
                buf += len;
                bufsz -= len;
        }

        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 bool visl_tpg_fill_codec_specific(struct visl_ctx *ctx,
                                         struct visl_run *run,
                                         char buf[], size_t bufsz)
{
        /*
         * To add variability, we need a value that is stable for a given
         * input but is different than already shown fields.
         * The pic order count value defines the display order of the frames
         * (which can be different than the decoding order that is shown with
         * the sequence number).
         * Therefore it is stable for a given input and will add a different
         * value that is more specific to the way the input is encoded.
         */
        switch (ctx->current_codec) {
        case VISL_CODEC_H264:
                scnprintf(buf, bufsz,
                          "H264: %u", run->h264.dpram->pic_order_cnt_lsb);
                break;
        case VISL_CODEC_HEVC:
                scnprintf(buf, bufsz,
                          "HEVC: %d", run->hevc.dpram->pic_order_cnt_val);
                break;
        default:
                return false;
        }

        return true;
}

static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
{
        u8 *basep[TPG_MAX_PLANES][2];
        char *buf = ctx->tpg_str_buf;
        char *tmp = buf;
        char *line_str;
        u32 line = 1;
        const u32 line_height = 16;
        u32 len;
        struct vb2_queue *out_q = &ctx->fh.m2m_ctx->out_q_ctx.q;
        struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
        struct v4l2_pix_format_mplane *coded_fmt = &ctx->coded_fmt.fmt.pix_mp;
        struct v4l2_pix_format_mplane *decoded_fmt = &ctx->decoded_fmt.fmt.pix_mp;
        u32 p;
        u32 i;

        for (p = 0; p < tpg_g_planes(&ctx->tpg); p++) {
                void *vbuf = plane_vaddr(&ctx->tpg,
                                         &run->dst->vb2_buf, p,
                                         ctx->tpg.bytesperline,
                                         ctx->tpg.buf_height);

                tpg_calc_text_basep(&ctx->tpg, basep, p, vbuf);
                tpg_fill_plane_buffer(&ctx->tpg, 0, p, vbuf);
        }

        visl_tpg_fill_sequence(ctx, run, buf, TPG_STR_BUF_SZ);
        tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
        frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
        frame_dprintk(ctx->dev, run->dst->sequence, "");
        line++;

        if (visl_tpg_fill_codec_specific(ctx, run, buf, TPG_STR_BUF_SZ)) {
                tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
                frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
                frame_dprintk(ctx->dev, run->dst->sequence, "");
                line++;
        }

        visl_get_ref_frames(ctx, buf, TPG_STR_BUF_SZ, run);

        while ((line_str = strsep(&tmp, "\n")) && strlen(line_str)) {
                tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, line_str);
                frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", line_str);
        }

        frame_dprintk(ctx->dev, run->dst->sequence, "");
        line++;

        scnprintf(buf,
                  TPG_STR_BUF_SZ,
                  "OUTPUT pixelformat: %c%c%c%c, resolution: %dx%d, num_planes: %d",
                  coded_fmt->pixelformat,
                  (coded_fmt->pixelformat >> 8) & 0xff,
                  (coded_fmt->pixelformat >> 16) & 0xff,
                  (coded_fmt->pixelformat >> 24) & 0xff,
                  coded_fmt->width,
                  coded_fmt->height,
                  coded_fmt->num_planes);

        tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
        frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);

        for (i = 0; i < coded_fmt->num_planes; i++) {
                scnprintf(buf,
                          TPG_STR_BUF_SZ,
                          "plane[%d]: bytesperline: %d, sizeimage: %d",
                          i,
                          coded_fmt->plane_fmt[i].bytesperline,
                          coded_fmt->plane_fmt[i].sizeimage);

                tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
                frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
        }

        if (tpg_verbose) {
                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 < vb2_get_num_buffers(out_q); i++) {
                        char entry[] = "index: %u, state: %s, request_fd: %d, ";
                        u32 old_len = len;
                        struct vb2_buffer *vb2;
                        char *q_status;

                        vb2 = vb2_get_buffer(out_q, i);
                        if (!vb2)
                                continue;

                        q_status = visl_get_vb2_state(vb2->state);

                        len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
                                         entry, i, q_status,
                                         to_vb2_v4l2_buffer(vb2)->request_fd);

                        len += visl_fill_bytesused(to_vb2_v4l2_buffer(vb2),
                                                   &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]);
                }
        }

        line++;
        frame_dprintk(ctx->dev, run->dst->sequence, "");

        scnprintf(buf,
                  TPG_STR_BUF_SZ,
                  "CAPTURE pixelformat: %c%c%c%c, resolution: %dx%d, num_planes: %d",
                  decoded_fmt->pixelformat,
                  (decoded_fmt->pixelformat >> 8) & 0xff,
                  (decoded_fmt->pixelformat >> 16) & 0xff,
                  (decoded_fmt->pixelformat >> 24) & 0xff,
                  decoded_fmt->width,
                  decoded_fmt->height,
                  decoded_fmt->num_planes);

        tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
        frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);

        for (i = 0; i < decoded_fmt->num_planes; i++) {
                scnprintf(buf,
                          TPG_STR_BUF_SZ,
                          "plane[%d]: bytesperline: %d, sizeimage: %d",
                          i,
                          decoded_fmt->plane_fmt[i].bytesperline,
                          decoded_fmt->plane_fmt[i].sizeimage);

                tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, buf);
                frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
        }

        if (tpg_verbose) {
                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 < vb2_get_num_buffers(cap_q); i++) {
                        u32 old_len = len;
                        struct vb2_buffer *vb2;
                        char *q_status;

                        vb2 = vb2_get_buffer(cap_q, i);
                        if (!vb2)
                                continue;

                        q_status = visl_get_vb2_state(vb2->state);

                        len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
                                         "index: %u, status: %s, timestamp: %llu, is_held: %d",
                                         vb2->index, q_status,
                                         vb2->timestamp,
                                         to_vb2_v4l2_buffer(vb2)->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]);
                }
        }
}

static void visl_trace_ctrls(struct visl_ctx *ctx, struct visl_run *run)
{
        int i;

        switch (ctx->current_codec) {
        default:
        case VISL_CODEC_NONE:
                break;
        case VISL_CODEC_FWHT:
                trace_v4l2_ctrl_fwht_params(run->fwht.params);
                break;
        case VISL_CODEC_MPEG2:
                trace_v4l2_ctrl_mpeg2_sequence(run->mpeg2.seq);
                trace_v4l2_ctrl_mpeg2_picture(run->mpeg2.pic);
                trace_v4l2_ctrl_mpeg2_quantisation(run->mpeg2.quant);
                break;
        case VISL_CODEC_VP8:
                trace_v4l2_ctrl_vp8_frame(run->vp8.frame);
                trace_v4l2_ctrl_vp8_entropy(run->vp8.frame);
                break;
        case VISL_CODEC_VP9:
                trace_v4l2_ctrl_vp9_frame(run->vp9.frame);
                trace_v4l2_ctrl_vp9_compressed_hdr(run->vp9.probs);
                trace_v4l2_ctrl_vp9_compressed_coeff(run->vp9.probs);
                trace_v4l2_vp9_mv_probs(&run->vp9.probs->mv);
                break;
        case VISL_CODEC_H264:
                trace_v4l2_ctrl_h264_sps(run->h264.sps);
                trace_v4l2_ctrl_h264_pps(run->h264.pps);
                trace_v4l2_ctrl_h264_scaling_matrix(run->h264.sm);
                trace_v4l2_ctrl_h264_slice_params(run->h264.spram);

                for (i = 0; i < ARRAY_SIZE(run->h264.spram->ref_pic_list0); i++)
                        trace_v4l2_h264_ref_pic_list0(&run->h264.spram->ref_pic_list0[i], i);
                for (i = 0; i < ARRAY_SIZE(run->h264.spram->ref_pic_list0); i++)
                        trace_v4l2_h264_ref_pic_list1(&run->h264.spram->ref_pic_list1[i], i);

                trace_v4l2_ctrl_h264_decode_params(run->h264.dpram);

                for (i = 0; i < ARRAY_SIZE(run->h264.dpram->dpb); i++)
                        trace_v4l2_h264_dpb_entry(&run->h264.dpram->dpb[i], i);

                trace_v4l2_ctrl_h264_pred_weights(run->h264.pwht);
                break;
        case VISL_CODEC_HEVC:
                trace_v4l2_ctrl_hevc_sps(run->hevc.sps);
                trace_v4l2_ctrl_hevc_pps(run->hevc.pps);
                trace_v4l2_ctrl_hevc_slice_params(run->hevc.spram);
                trace_v4l2_ctrl_hevc_scaling_matrix(run->hevc.sm);
                trace_v4l2_ctrl_hevc_decode_params(run->hevc.dpram);

                for (i = 0; i < ARRAY_SIZE(run->hevc.dpram->dpb); i++)
                        trace_v4l2_hevc_dpb_entry(&run->hevc.dpram->dpb[i]);

                trace_v4l2_hevc_pred_weight_table(&run->hevc.spram->pred_weight_table);
                trace_v4l2_ctrl_hevc_ext_sps_lt_rps(run->hevc.rps_lt);
                trace_v4l2_ctrl_hevc_ext_sps_st_rps(run->hevc.rps_st);

                break;
        case VISL_CODEC_AV1:
                trace_v4l2_ctrl_av1_sequence(run->av1.seq);
                trace_v4l2_ctrl_av1_frame(run->av1.frame);
                trace_v4l2_ctrl_av1_film_grain(run->av1.grain);
                trace_v4l2_ctrl_av1_tile_group_entry(run->av1.tge);
                break;
        }
}

void visl_device_run(void *priv)
{
        struct visl_ctx *ctx = priv;
        struct visl_run run = {};
        struct media_request *src_req;

        run.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
        run.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);

        /* Apply request(s) controls if needed. */
        src_req = run.src->vb2_buf.req_obj.req;

        if (src_req)
                v4l2_ctrl_request_setup(src_req, &ctx->hdl);

        v4l2_m2m_buf_copy_metadata(run.src, run.dst);
        run.dst->sequence = ctx->q_data[V4L2_M2M_DST].sequence++;
        run.src->sequence = ctx->q_data[V4L2_M2M_SRC].sequence++;
        run.dst->field = ctx->decoded_fmt.fmt.pix.field;

        switch (ctx->current_codec) {
        default:
        case VISL_CODEC_NONE:
                break;
        case VISL_CODEC_FWHT:
                run.fwht.params = visl_find_control_data(ctx, V4L2_CID_STATELESS_FWHT_PARAMS);
                break;
        case VISL_CODEC_MPEG2:
                run.mpeg2.seq = visl_find_control_data(ctx, V4L2_CID_STATELESS_MPEG2_SEQUENCE);
                run.mpeg2.pic = visl_find_control_data(ctx, V4L2_CID_STATELESS_MPEG2_PICTURE);
                run.mpeg2.quant = visl_find_control_data(ctx,
                                                         V4L2_CID_STATELESS_MPEG2_QUANTISATION);
                break;
        case VISL_CODEC_VP8:
                run.vp8.frame = visl_find_control_data(ctx, V4L2_CID_STATELESS_VP8_FRAME);
                break;
        case VISL_CODEC_VP9:
                run.vp9.frame = visl_find_control_data(ctx, V4L2_CID_STATELESS_VP9_FRAME);
                run.vp9.probs = visl_find_control_data(ctx, V4L2_CID_STATELESS_VP9_COMPRESSED_HDR);
                break;
        case VISL_CODEC_H264:
                run.h264.sps = visl_find_control_data(ctx, V4L2_CID_STATELESS_H264_SPS);
                run.h264.pps = visl_find_control_data(ctx, V4L2_CID_STATELESS_H264_PPS);
                run.h264.sm = visl_find_control_data(ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX);
                run.h264.spram = visl_find_control_data(ctx, V4L2_CID_STATELESS_H264_SLICE_PARAMS);
                run.h264.dpram = visl_find_control_data(ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS);
                run.h264.pwht = visl_find_control_data(ctx, V4L2_CID_STATELESS_H264_PRED_WEIGHTS);
                break;
        case VISL_CODEC_HEVC:
                run.hevc.sps = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SPS);
                run.hevc.pps = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_PPS);
                run.hevc.spram = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
                run.hevc.sm = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
                run.hevc.dpram = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
                run.hevc.rps_lt = visl_find_control_data(ctx,
                                                         V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS);
                run.hevc.rps_st = visl_find_control_data(ctx,
                                                         V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS);
                break;
        case VISL_CODEC_AV1:
                run.av1.seq = visl_find_control_data(ctx, V4L2_CID_STATELESS_AV1_SEQUENCE);
                run.av1.frame = visl_find_control_data(ctx, V4L2_CID_STATELESS_AV1_FRAME);
                run.av1.tge = visl_find_control_data(ctx, V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY);
                run.av1.grain = visl_find_control_data(ctx, V4L2_CID_STATELESS_AV1_FILM_GRAIN);
                break;
        }

        frame_dprintk(ctx->dev, run.dst->sequence,
                      "Got OUTPUT buffer sequence %d, timestamp %llu\n",
                      run.src->sequence, run.src->vb2_buf.timestamp);

        frame_dprintk(ctx->dev, run.dst->sequence,
                      "Got CAPTURE buffer sequence %d, timestamp %llu\n",
                      run.dst->sequence, run.dst->vb2_buf.timestamp);

        visl_tpg_fill(ctx, &run);
        visl_trace_ctrls(ctx, &run);

        if (bitstream_trace_frame_start > -1 &&
            run.dst->sequence >= bitstream_trace_frame_start &&
            run.dst->sequence < bitstream_trace_frame_start + bitstream_trace_nframes)
                visl_trace_bitstream(ctx, &run);

        /* Complete request(s) controls if needed. */
        if (src_req)
                v4l2_ctrl_request_complete(src_req, &ctx->hdl);

        if (visl_transtime_ms)
                usleep_range(visl_transtime_ms * 1000, 2 * visl_transtime_ms * 1000);

        v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev,
                                         ctx->fh.m2m_ctx, VB2_BUF_STATE_DONE);
}