1 // SPDX-License-Identifier: GPL-2.0
3 * A virtual stateless decoder device for stateless uAPI development purposes.
5 * This tool's objective is to help the development and testing of userspace
6 * applications that use the V4L2 stateless API to decode media.
8 * A userspace implementation can use visl to run a decoding loop even when no
9 * hardware is available or when the kernel uAPI for the codec has not been
10 * upstreamed yet. This can reveal bugs at an early stage.
12 * This driver can also trace the contents of the V4L2 controls submitted to it.
13 * It can also dump the contents of the vb2 buffers through a debugfs
14 * interface. This is in many ways similar to the tracing infrastructure
15 * available for other popular encode/decode APIs out there and can help develop
16 * a userspace application by using another (working) one as a reference.
18 * Note that no actual decoding of video frames is performed by visl. The V4L2
19 * test pattern generator is used to write various debug information to the
20 * capture buffers instead.
22 * Copyright (C) 2022 Collabora, Ltd.
24 * Based on the vim2m driver, that is:
26 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
27 * Pawel Osciak, <pawel@osciak.com>
28 * Marek Szyprowski, <m.szyprowski@samsung.com>
30 * Based on the vicodec driver, that is:
32 * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
34 * Based on the Cedrus VPU driver, that is:
36 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
37 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
38 * Copyright (C) 2018 Bootlin
41 #include <linux/debugfs.h>
42 #include <linux/module.h>
43 #include <linux/platform_device.h>
44 #include <media/v4l2-ctrls.h>
45 #include <media/v4l2-device.h>
46 #include <media/v4l2-ioctl.h>
47 #include <media/v4l2-mem2mem.h>
51 #include "visl-debugfs.h"
52 #include "visl-video.h"
54 unsigned int visl_debug
;
55 module_param(visl_debug
, uint
, 0644);
56 MODULE_PARM_DESC(visl_debug
, " activates debug info");
58 unsigned int visl_transtime_ms
;
59 module_param(visl_transtime_ms
, uint
, 0644);
60 MODULE_PARM_DESC(visl_transtime_ms
, " simulated process time in milliseconds.");
63 * dprintk can be slow through serial. This lets one limit the tracing to a
64 * particular number of frames
66 int visl_dprintk_frame_start
= -1;
67 module_param(visl_dprintk_frame_start
, int, 0444);
68 MODULE_PARM_DESC(visl_dprintk_frame_start
,
69 " a frame number to start tracing with dprintk");
71 unsigned int visl_dprintk_nframes
;
72 module_param(visl_dprintk_nframes
, uint
, 0444);
73 MODULE_PARM_DESC(visl_dprintk_nframes
,
74 " the number of frames to trace with dprintk");
76 bool keep_bitstream_buffers
;
77 module_param(keep_bitstream_buffers
, bool, 0444);
78 MODULE_PARM_DESC(keep_bitstream_buffers
,
79 " keep bitstream buffers in debugfs after streaming is stopped");
81 int bitstream_trace_frame_start
= -1;
82 module_param(bitstream_trace_frame_start
, int, 0444);
83 MODULE_PARM_DESC(bitstream_trace_frame_start
,
84 " a frame number to start dumping the bitstream through debugfs");
86 unsigned int bitstream_trace_nframes
;
87 module_param(bitstream_trace_nframes
, uint
, 0444);
88 MODULE_PARM_DESC(bitstream_trace_nframes
,
89 " the number of frames to dump the bitstream through debugfs");
92 module_param(tpg_verbose
, bool, 0644);
93 MODULE_PARM_DESC(tpg_verbose
,
94 " add more verbose information on the generated output frames");
96 static const struct visl_ctrl_desc visl_fwht_ctrl_descs
[] = {
98 .cfg
.id
= V4L2_CID_STATELESS_FWHT_PARAMS
,
102 const struct visl_ctrls visl_fwht_ctrls
= {
103 .ctrls
= visl_fwht_ctrl_descs
,
104 .num_ctrls
= ARRAY_SIZE(visl_fwht_ctrl_descs
)
107 static const struct visl_ctrl_desc visl_mpeg2_ctrl_descs
[] = {
109 .cfg
.id
= V4L2_CID_STATELESS_MPEG2_SEQUENCE
,
112 .cfg
.id
= V4L2_CID_STATELESS_MPEG2_PICTURE
,
115 .cfg
.id
= V4L2_CID_STATELESS_MPEG2_QUANTISATION
,
119 const struct visl_ctrls visl_mpeg2_ctrls
= {
120 .ctrls
= visl_mpeg2_ctrl_descs
,
121 .num_ctrls
= ARRAY_SIZE(visl_mpeg2_ctrl_descs
),
124 static const struct visl_ctrl_desc visl_vp8_ctrl_descs
[] = {
126 .cfg
.id
= V4L2_CID_STATELESS_VP8_FRAME
,
130 const struct visl_ctrls visl_vp8_ctrls
= {
131 .ctrls
= visl_vp8_ctrl_descs
,
132 .num_ctrls
= ARRAY_SIZE(visl_vp8_ctrl_descs
),
135 static const struct visl_ctrl_desc visl_vp9_ctrl_descs
[] = {
137 .cfg
.id
= V4L2_CID_STATELESS_VP9_FRAME
,
140 .cfg
.id
= V4L2_CID_STATELESS_VP9_COMPRESSED_HDR
,
144 const struct visl_ctrls visl_vp9_ctrls
= {
145 .ctrls
= visl_vp9_ctrl_descs
,
146 .num_ctrls
= ARRAY_SIZE(visl_vp9_ctrl_descs
),
149 static const struct visl_ctrl_desc visl_h264_ctrl_descs
[] = {
151 .cfg
.id
= V4L2_CID_STATELESS_H264_DECODE_PARAMS
,
154 .cfg
.id
= V4L2_CID_STATELESS_H264_SPS
,
157 .cfg
.id
= V4L2_CID_STATELESS_H264_PPS
,
160 .cfg
.id
= V4L2_CID_STATELESS_H264_SCALING_MATRIX
,
163 .cfg
.id
= V4L2_CID_STATELESS_H264_DECODE_MODE
,
166 .cfg
.id
= V4L2_CID_STATELESS_H264_START_CODE
,
169 .cfg
.id
= V4L2_CID_STATELESS_H264_SLICE_PARAMS
,
172 .cfg
.id
= V4L2_CID_STATELESS_H264_PRED_WEIGHTS
,
176 const struct visl_ctrls visl_h264_ctrls
= {
177 .ctrls
= visl_h264_ctrl_descs
,
178 .num_ctrls
= ARRAY_SIZE(visl_h264_ctrl_descs
),
181 static const struct visl_ctrl_desc visl_hevc_ctrl_descs
[] = {
183 .cfg
.id
= V4L2_CID_STATELESS_HEVC_SPS
,
186 .cfg
.id
= V4L2_CID_STATELESS_HEVC_PPS
,
189 .cfg
.id
= V4L2_CID_STATELESS_HEVC_SLICE_PARAMS
,
190 /* The absolute maximum for level > 6 */
194 .cfg
.id
= V4L2_CID_STATELESS_HEVC_SCALING_MATRIX
,
197 .cfg
.id
= V4L2_CID_STATELESS_HEVC_DECODE_PARAMS
,
200 .cfg
.id
= V4L2_CID_STATELESS_HEVC_DECODE_MODE
,
203 .cfg
.id
= V4L2_CID_STATELESS_HEVC_START_CODE
,
206 .cfg
.id
= V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS
,
208 .cfg
.max
= 0xffffffff,
214 const struct visl_ctrls visl_hevc_ctrls
= {
215 .ctrls
= visl_hevc_ctrl_descs
,
216 .num_ctrls
= ARRAY_SIZE(visl_hevc_ctrl_descs
),
219 static const struct visl_ctrl_desc visl_av1_ctrl_descs
[] = {
221 .cfg
.id
= V4L2_CID_STATELESS_AV1_FRAME
,
224 .cfg
.id
= V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY
,
225 .cfg
.dims
= { V4L2_AV1_MAX_TILE_COUNT
},
228 .cfg
.id
= V4L2_CID_STATELESS_AV1_SEQUENCE
,
231 .cfg
.id
= V4L2_CID_STATELESS_AV1_FILM_GRAIN
,
235 const struct visl_ctrls visl_av1_ctrls
= {
236 .ctrls
= visl_av1_ctrl_descs
,
237 .num_ctrls
= ARRAY_SIZE(visl_av1_ctrl_descs
),
240 struct v4l2_ctrl
*visl_find_control(struct visl_ctx
*ctx
, u32 id
)
242 struct v4l2_ctrl_handler
*hdl
= &ctx
->hdl
;
244 return v4l2_ctrl_find(hdl
, id
);
247 void *visl_find_control_data(struct visl_ctx
*ctx
, u32 id
)
249 struct v4l2_ctrl
*ctrl
;
251 ctrl
= visl_find_control(ctx
, id
);
253 return ctrl
->p_cur
.p
;
258 u32
visl_control_num_elems(struct visl_ctx
*ctx
, u32 id
)
260 struct v4l2_ctrl
*ctrl
;
262 ctrl
= visl_find_control(ctx
, id
);
269 static void visl_device_release(struct video_device
*vdev
)
271 struct visl_dev
*dev
= container_of(vdev
, struct visl_dev
, vfd
);
273 v4l2_device_unregister(&dev
->v4l2_dev
);
274 v4l2_m2m_release(dev
->m2m_dev
);
275 media_device_cleanup(&dev
->mdev
);
276 visl_debugfs_deinit(dev
);
280 #define VISL_CONTROLS_COUNT ARRAY_SIZE(visl_controls)
282 static int visl_init_ctrls(struct visl_ctx
*ctx
)
284 struct visl_dev
*dev
= ctx
->dev
;
285 struct v4l2_ctrl_handler
*hdl
= &ctx
->hdl
;
286 unsigned int ctrl_cnt
= 0;
289 const struct visl_ctrls
*ctrls
;
291 for (i
= 0; i
< num_coded_fmts
; i
++)
292 ctrl_cnt
+= visl_coded_fmts
[i
].ctrls
->num_ctrls
;
294 v4l2_ctrl_handler_init(hdl
, ctrl_cnt
);
296 for (i
= 0; i
< num_coded_fmts
; i
++) {
297 ctrls
= visl_coded_fmts
[i
].ctrls
;
298 for (j
= 0; j
< ctrls
->num_ctrls
; j
++)
299 v4l2_ctrl_new_custom(hdl
, &ctrls
->ctrls
[j
].cfg
, NULL
);
303 v4l2_err(&dev
->v4l2_dev
,
304 "Failed to initialize control handler\n");
305 v4l2_ctrl_handler_free(hdl
);
309 ctx
->fh
.ctrl_handler
= hdl
;
310 v4l2_ctrl_handler_setup(hdl
);
315 static int visl_open(struct file
*file
)
317 struct visl_dev
*dev
= video_drvdata(file
);
318 struct visl_ctx
*ctx
= NULL
;
321 if (mutex_lock_interruptible(&dev
->dev_mutex
))
323 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
329 ctx
->tpg_str_buf
= kzalloc(TPG_STR_BUF_SZ
, GFP_KERNEL
);
331 v4l2_fh_init(&ctx
->fh
, video_devdata(file
));
332 file
->private_data
= &ctx
->fh
;
335 rc
= visl_init_ctrls(ctx
);
339 ctx
->fh
.m2m_ctx
= v4l2_m2m_ctx_init(dev
->m2m_dev
, ctx
, &visl_queue_init
);
341 mutex_init(&ctx
->vb_mutex
);
343 if (IS_ERR(ctx
->fh
.m2m_ctx
)) {
344 rc
= PTR_ERR(ctx
->fh
.m2m_ctx
);
348 rc
= visl_set_default_format(ctx
);
352 v4l2_fh_add(&ctx
->fh
);
354 dprintk(dev
, "Created instance: %p, m2m_ctx: %p\n",
355 ctx
, ctx
->fh
.m2m_ctx
);
357 mutex_unlock(&dev
->dev_mutex
);
361 v4l2_m2m_ctx_release(ctx
->fh
.m2m_ctx
);
363 v4l2_ctrl_handler_free(&ctx
->hdl
);
364 v4l2_fh_exit(&ctx
->fh
);
366 kfree(ctx
->tpg_str_buf
);
369 mutex_unlock(&dev
->dev_mutex
);
373 static int visl_release(struct file
*file
)
375 struct visl_dev
*dev
= video_drvdata(file
);
376 struct visl_ctx
*ctx
= visl_file_to_ctx(file
);
378 dprintk(dev
, "Releasing instance %p\n", ctx
);
381 v4l2_fh_del(&ctx
->fh
);
382 v4l2_fh_exit(&ctx
->fh
);
383 v4l2_ctrl_handler_free(&ctx
->hdl
);
384 mutex_lock(&dev
->dev_mutex
);
385 v4l2_m2m_ctx_release(ctx
->fh
.m2m_ctx
);
386 mutex_unlock(&dev
->dev_mutex
);
388 kfree(ctx
->tpg_str_buf
);
394 static const struct v4l2_file_operations visl_fops
= {
395 .owner
= THIS_MODULE
,
397 .release
= visl_release
,
398 .poll
= v4l2_m2m_fop_poll
,
399 .unlocked_ioctl
= video_ioctl2
,
400 .mmap
= v4l2_m2m_fop_mmap
,
403 static const struct video_device visl_videodev
= {
405 .vfl_dir
= VFL_DIR_M2M
,
407 .ioctl_ops
= &visl_ioctl_ops
,
409 .release
= visl_device_release
,
410 .device_caps
= V4L2_CAP_VIDEO_M2M_MPLANE
| V4L2_CAP_STREAMING
,
413 static const struct v4l2_m2m_ops visl_m2m_ops
= {
414 .device_run
= visl_device_run
,
417 static const struct media_device_ops visl_m2m_media_ops
= {
418 .req_validate
= visl_request_validate
,
419 .req_queue
= v4l2_m2m_request_queue
,
422 static int visl_probe(struct platform_device
*pdev
)
424 struct visl_dev
*dev
;
425 struct video_device
*vfd
;
429 dev
= kzalloc(sizeof(*dev
), GFP_KERNEL
);
433 ret
= v4l2_device_register(&pdev
->dev
, &dev
->v4l2_dev
);
437 mutex_init(&dev
->dev_mutex
);
439 dev
->vfd
= visl_videodev
;
441 vfd
->lock
= &dev
->dev_mutex
;
442 vfd
->v4l2_dev
= &dev
->v4l2_dev
;
444 video_set_drvdata(vfd
, dev
);
446 platform_set_drvdata(pdev
, dev
);
448 dev
->m2m_dev
= v4l2_m2m_init(&visl_m2m_ops
);
449 if (IS_ERR(dev
->m2m_dev
)) {
450 v4l2_err(&dev
->v4l2_dev
, "Failed to init mem2mem device\n");
451 ret
= PTR_ERR(dev
->m2m_dev
);
456 dev
->mdev
.dev
= &pdev
->dev
;
457 strscpy(dev
->mdev
.model
, "visl", sizeof(dev
->mdev
.model
));
458 strscpy(dev
->mdev
.bus_info
, "platform:visl",
459 sizeof(dev
->mdev
.bus_info
));
460 media_device_init(&dev
->mdev
);
461 dev
->mdev
.ops
= &visl_m2m_media_ops
;
462 dev
->v4l2_dev
.mdev
= &dev
->mdev
;
464 ret
= video_register_device(vfd
, VFL_TYPE_VIDEO
, -1);
466 v4l2_err(&dev
->v4l2_dev
, "Failed to register video device\n");
470 v4l2_info(&dev
->v4l2_dev
,
471 "Device registered as /dev/video%d\n", vfd
->num
);
473 ret
= v4l2_m2m_register_media_controller(dev
->m2m_dev
, vfd
,
474 MEDIA_ENT_F_PROC_VIDEO_DECODER
);
476 v4l2_err(&dev
->v4l2_dev
, "Failed to init mem2mem media controller\n");
480 ret
= media_device_register(&dev
->mdev
);
482 v4l2_err(&dev
->v4l2_dev
, "Failed to register mem2mem media device\n");
486 rc
= visl_debugfs_init(dev
);
488 dprintk(dev
, "visl_debugfs_init failed: %d\n"
489 "Continuing without debugfs support\n", rc
);
494 v4l2_m2m_unregister_media_controller(dev
->m2m_dev
);
496 video_unregister_device(&dev
->vfd
);
497 /* visl_device_release called by video_unregister_device to release various objects */
500 v4l2_m2m_release(dev
->m2m_dev
);
502 v4l2_device_unregister(&dev
->v4l2_dev
);
509 static void visl_remove(struct platform_device
*pdev
)
511 struct visl_dev
*dev
= platform_get_drvdata(pdev
);
513 v4l2_info(&dev
->v4l2_dev
, "Removing " VISL_NAME
);
515 #ifdef CONFIG_MEDIA_CONTROLLER
516 if (media_devnode_is_registered(dev
->mdev
.devnode
)) {
517 media_device_unregister(&dev
->mdev
);
518 v4l2_m2m_unregister_media_controller(dev
->m2m_dev
);
521 video_unregister_device(&dev
->vfd
);
524 static struct platform_driver visl_pdrv
= {
526 .remove
= visl_remove
,
532 static void visl_dev_release(struct device
*dev
) {}
534 static struct platform_device visl_pdev
= {
536 .dev
.release
= visl_dev_release
,
539 static void __exit
visl_exit(void)
541 platform_driver_unregister(&visl_pdrv
);
542 platform_device_unregister(&visl_pdev
);
545 static int __init
visl_init(void)
549 ret
= platform_device_register(&visl_pdev
);
553 ret
= platform_driver_register(&visl_pdrv
);
555 platform_device_unregister(&visl_pdev
);
560 MODULE_DESCRIPTION("Virtual stateless decoder device");
561 MODULE_AUTHOR("Daniel Almeida <daniel.almeida@collabora.com>");
562 MODULE_LICENSE("GPL");
564 module_init(visl_init
);
565 module_exit(visl_exit
);