Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ After running `make`, you should be able to generate the following files:

Before loading this kernel module, you have to satisfy its dependency:
```shell
$ sudo modprobe -a videobuf2_vmalloc videobuf2_v4l2
$ sudo modprobe -a videobuf2_vmalloc videobuf2_v4l2 videobuf2-dma-contig
```

The module can be loaded to Linux kernel by runnning the command:
Expand Down Expand Up @@ -56,9 +56,15 @@ $ sudo ./vcam-util -l
You should get:
```
Available virtual V4L2 compatible devices:
1. fbX(640,480,rgb24) -> /dev/video0
1. fbX(640,480,rgb24,mmap) -> /dev/video0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add note for DMA-BUF to illustrate the results.

```

The default memory type is MMAP. You can switch to DMA-BUF using the `-t` option, for example:
```shell
$ sudo ./vcam-util -c -t dmabuf
```
The DMA-BUF framework provides a unified way to share buffers across multiple devices.

You can use this command to check if the driver is ok:
```shell
$ sudo v4l2-compliance -d /dev/videoX -f
Expand Down
2 changes: 2 additions & 0 deletions control.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ static int control_iocontrol_get_device(struct vcam_device_spec *dev_spec)
dev_spec->width = dev->fb_spec.xres_virtual;
dev_spec->height = dev->fb_spec.yres_virtual;
dev_spec->pix_fmt = dev->fb_spec.pix_fmt;
dev_spec->mem_type = dev->fb_spec.mem_type;
dev_spec->cropratio = dev->fb_spec.cropratio;

strncpy((char *) &dev_spec->fb_node, (const char *) vcamfb_get_devnode(dev),
Expand Down Expand Up @@ -174,6 +175,7 @@ static struct vcam_device_spec default_vcam_spec = {
.height = 480,
.cropratio = {.numerator = 3, .denominator = 4},
.pix_fmt = VCAM_PIXFMT_RGB24,
.mem_type = VCAM_MEMORY_MMAP,
};

int request_vcam_device(struct vcam_device_spec *dev_spec)
Expand Down
3 changes: 3 additions & 0 deletions device.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ struct vcam_device {
struct v4l2_pix_format output_format;
struct v4l2_pix_format input_format;

/* Memory type */
memtype_t mem_type;

/* Conversion switches */
bool conv_pixfmt_on;
bool conv_res_on;
Expand Down
41 changes: 34 additions & 7 deletions vcam-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@

#include "vcam.h"

static const char *short_options = "hcm:r:ls:p:d:";
static const char *short_options = "hcm:r:ls:p:d:t:";

const struct option long_options[] = {
{"help", 0, NULL, 'h'}, {"create", 0, NULL, 'c'},
{"modify", 1, NULL, 'm'}, {"list", 0, NULL, 'l'},
{"size", 1, NULL, 's'}, {"pixfmt", 1, NULL, 'p'},
{"device", 1, NULL, 'd'}, {"remove", 1, NULL, 'r'},
{NULL, 0, NULL, 0}};
{"help", 0, NULL, 'h'}, {"create", 0, NULL, 'c'},
{"modify", 1, NULL, 'm'}, {"list", 0, NULL, 'l'},
{"size", 1, NULL, 's'}, {"pixfmt", 1, NULL, 'p'},
{"device", 1, NULL, 'd'}, {"remove", 1, NULL, 'r'},
{"memtype", 1, NULL, 't'}, {NULL, 0, NULL, 0}};

const char *help =
" -h --help Print this informations.\n"
Expand All @@ -37,6 +37,7 @@ const char *help =
"and apply with crop ratio.\n"
"\n"
" -p --pixfmt pix_fmt Specify pixel format (rgb24,yuyv).\n"
" -t --memtype mem_type Specify memory type (mmap,dmabuf).\n"
" -d --device /dev/* Control device node.\n";

enum ACTION { ACTION_NONE, ACTION_CREATE, ACTION_DESTROY, ACTION_MODIFY };
Expand All @@ -45,6 +46,7 @@ struct vcam_device_spec device_template = {
.width = 640,
.height = 480,
.pix_fmt = VCAM_PIXFMT_RGB24,
.mem_type = VCAM_MEMORY_MMAP,
.video_node = "",
.fb_node = "",
};
Expand Down Expand Up @@ -102,6 +104,14 @@ int determine_pixfmt(char *pixfmt_str)
return -1;
}

int determine_memtype(char *memtype_str)
{
if (!strncmp(memtype_str, "mmap", 4))
return VCAM_MEMORY_MMAP;
if (!strncmp(memtype_str, "dmabuf", 6))
return VCAM_MEMORY_DMABUF;
return -1;
}
int create_device(struct vcam_device_spec *dev)
{
int fd = open(ctl_path, O_RDWR);
Expand All @@ -118,6 +128,9 @@ int create_device(struct vcam_device_spec *dev)
if (!dev->pix_fmt)
dev->pix_fmt = device_template.pix_fmt;

if (!dev->mem_type)
dev->mem_type = device_template.mem_type;

int res = ioctl(fd, VCAM_IOCTL_CREATE_DEVICE, dev);
if (res) {
fprintf(stderr, "Failed to create a new device.\n");
Expand Down Expand Up @@ -170,6 +183,9 @@ int modify_device(struct vcam_device_spec *dev)
if (!dev->pix_fmt)
dev->pix_fmt = orig_dev.pix_fmt;

if (!dev->mem_type)
dev->mem_type = orig_dev.mem_type;

if (!dev->cropratio.numerator || !dev->cropratio.denominator)
dev->cropratio = orig_dev.cropratio;

Expand All @@ -195,10 +211,11 @@ int list_devices()
printf("Available virtual V4L2 compatible devices:\n");
while (!ioctl(fd, VCAM_IOCTL_GET_DEVICE, &dev)) {
dev.idx++;
printf("%d. %s(%d,%d,%d/%d,%s) -> %s\n", dev.idx, dev.fb_node,
printf("%d. %s(%d,%d,%d/%d,%s,%s) -> %s\n", dev.idx, dev.fb_node,
dev.width, dev.height, dev.cropratio.numerator,
dev.cropratio.denominator,
dev.pix_fmt == VCAM_PIXFMT_RGB24 ? "rgb24" : "yuyv",
dev.mem_type == VCAM_MEMORY_MMAP ? "mmap" : "dmabuf",
dev.video_node);
}
close(fd);
Expand Down Expand Up @@ -258,6 +275,16 @@ int main(int argc, char *argv[])
dev.pix_fmt = (char) tmp;
printf("Setting pixel format to %s.\n", optarg);
break;
case 't':
tmp = determine_memtype(optarg);
if (tmp < 0) {
fprintf(stderr, "Failed to recognize memory type %s.\n",
optarg);
exit(-1);
}
dev.mem_type = (char) tmp;
printf("Setting memory type to %s.\n", optarg);
break;
case 'd':
printf("Using device %s.\n", optarg);
strncpy(ctl_path, optarg, sizeof(ctl_path) - 1);
Expand Down
2 changes: 2 additions & 0 deletions vcam.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define VCAM_IOCTL_MODIFY_SETTING 0x555

typedef enum { VCAM_PIXFMT_RGB24 = 0x01, VCAM_PIXFMT_YUYV = 0x02 } pixfmt_t;
typedef enum { VCAM_MEMORY_MMAP = 0, VCAM_MEMORY_DMABUF = 2 } memtype_t;

struct crop_ratio {
__u32 numerator;
Expand All @@ -27,6 +28,7 @@ struct vcam_device_spec {
struct crop_ratio cropratio;

pixfmt_t pix_fmt;
memtype_t mem_type;
char video_node[64];
char fb_node[64];
};
Expand Down
32 changes: 30 additions & 2 deletions videobuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <linux/spinlock.h>
#include <linux/vmalloc.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-vmalloc.h>

#include "videobuf.h"
Expand Down Expand Up @@ -114,6 +115,23 @@ static void vcam_outbuf_unlock(struct vb2_queue *vq)
mutex_unlock(&dev->vcam_mutex);
}

static int vcam_buf_init(struct vb2_buffer *vb)
{
struct vcam_out_buffer *buf =
container_of(vb, struct vcam_out_buffer, vb.vb2_buf);

buf->filled = 0;
INIT_LIST_HEAD(&buf->list);

pr_debug("vcam_buf_init: buffer initialized\n");
return 0;
}

static void vcam_buf_cleanup(struct vb2_buffer *vb)
{
pr_debug("vcam_buf_cleanup called\n");
}

static const struct vb2_ops vcam_vb2_ops = {
.queue_setup = vcam_out_queue_setup,
.buf_prepare = vcam_out_buffer_prepare,
Expand All @@ -122,19 +140,29 @@ static const struct vb2_ops vcam_vb2_ops = {
.stop_streaming = vcam_stop_streaming,
.wait_prepare = vcam_outbuf_unlock,
.wait_finish = vcam_outbuf_lock,
.buf_init = vcam_buf_init,
.buf_cleanup = vcam_buf_cleanup,
};

int vcam_out_videobuf2_setup(struct vcam_device *dev)
{
struct vb2_queue *q = &dev->vb_out_vidq;

q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct vcam_out_buffer);
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->ops = &vcam_vb2_ops;
q->mem_ops = &vb2_vmalloc_memops;
pr_info("memory type %d\n", dev->mem_type);
switch (dev->mem_type) {
case VCAM_MEMORY_MMAP:
q->mem_ops = &vb2_vmalloc_memops;
break;
case VCAM_MEMORY_DMABUF:
q->mem_ops = &vb2_dma_contig_memops;
break;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0)
q->min_queued_buffers = 2;
#else
Expand Down
Loading