03_从0编写一个虚拟摄像头驱动#
参考资料:
深入理解linux内核v4l2框架之videobuf2:https://blog.csdn.net/yyjsword/article/details/9243717
V4L2框架-videobuf2:https://blog.csdn.net/u013904227/article/details/81054611
1. 回顾与编写程序框架#
本节视频对应的代码:
doc_and_source_for_drivers\
IMX6ULL\source\
13_V4L2\
06_virtual_driver\
01_virtual_driver_framework
参考《1.3.2 videobuffer2的3个ops》里面完整的注册流程。
完整的注册流程(参考drivers\media\usb\airspy\airspy.c
):
static struct video_device airspy_template = {
.name = "AirSpy SDR",
.release = video_device_release_empty,
.fops = &airspy_fops,
.ioctl_ops = &airspy_ioctl_ops,
};
/* 构造一个vb2_queue */
/* Init videobuf2 queue structure */
s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
s->vb_queue.drv_priv = s;
s->vb_queue.buf_struct_size = sizeof(struct airspy_frame_buf);
s->vb_queue.ops = &airspy_vb2_ops; // vb2_ops, 硬件相关的操作函数
s->vb_queue.mem_ops = &vb2_vmalloc_memops; // vb2_mem_ops, 辅助结构体,用于mem ops(alloc、mmap)
s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
ret = vb2_queue_init(&s->vb_queue);
q->buf_ops = &v4l2_buf_ops; // vb2_buf_ops, 用于APP和驱动传递参数
// 分配/设置video_device结构体
s->vdev = airspy_template;
s->vdev.queue = &s->vb_queue; // 指向前面构造的vb2_queue
// 初始化一个v4l2_device结构体(起辅助作用)
/* Register the v4l2_device structure */
s->v4l2_dev.release = airspy_video_release;
ret = v4l2_device_register(&intf->dev, &s->v4l2_dev);
// video_device和4l2_device建立联系
s->vdev.v4l2_dev = &s->v4l2_dev;
// 注册video_device结构体
ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
__video_register_device
// 根据次设备号把video_device结构体放入数组
video_device[vdev->minor] = vdev;
// 注册字符设备驱动程序
vdev->cdev->ops = &v4l2_fops;
vdev->cdev->owner = owner;
ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
2. 编写硬件相关代码#
本节视频对应的代码:
doc_and_source_for_drivers\
IMX6ULL\source\
13_V4L2\
06_virtual_driver\
02_virtual_driver_hardware
2.1 ioctl相关的代码#
2.2 buffer相关的代码#
2.3 数据传输#
linux下可以使用如下命令:
hexdump -v -e '8/1 "0x%02x, " "\n"' red.jpg
windows下使用winhex工具,视频有教。
3. 上机测试#
可以禁止LCD自动黑屏,执行以下命令即可:
#close lcd sleep
echo -e "\033[9;0]" > /dev/tty1
echo -e "\033[?25l" > /dev/tty1
3.1 IMX6ULL#
先关闭GUI:
[root@100ask:~]# mv /etc/init.d/S99myirhmi2 /root/
[root@100ask:~]# mv /etc/init.d/*lvgl* /root/
[root@100ask:~]# reboot
然后编译驱动:13_V4L2\06_virtual_driver\04_virtual_driver_ok\
编译APP:13_V4L2\02_video2lcd\
测试:
insmod my_video_drv.ko
./video2lcd /dev/video1
3.2 STM32MP157#
3.2.1 编译#
先编译内核,编译模块:
make 100ask_stm32mp157_pro_defconfig
make uImage LOADADDR=0xC2000040 -j 12
make modules -j 12
然后编译驱动:13_V4L2\06_virtual_driver\04_virtual_driver_ok\
编译APP:13_V4L2\02_video2lcd\
3.2.2 在开发板上操作#
关闭GUI:
systemctl stop myir //关闭自带的GUI程序
测试:
modprobe videobuf2-common
modprobe videobuf2-v4l2
modprobe videobuf2-memops
modprobe videobuf2-vmalloc
insmod my_video_drv.ko
./video2lcd /dev/video0