【Linux驱动】Linux--V4L2视频驱动框架

Linux–V4L2驱动框架

一、V4L2 框架

v4l2驱动框架主要的对象有video_device、v4l2_device、v4l2_subdev、videobuf

  • video_device

    一个字符设备,为用户空间提供设备节点(/dev/videox),提供系统调用的相关操作(open、ioctl…)

  • v4l2_device

    嵌入到video_device中,表示一个v4l2设备的实例

  • v4l2_subdev

    依附在v4l2_device之下,并表示一个v4l2设备的子设备,一个v4l2_devide下可以有多个sub_device

  • videobuf

    v4l2驱动的缓存管理

v4l2_device和v4l2_subdev的关系:

subdev的设计目的是为了多路复用,就是用一个v4l2_device可以挂接多个v4l2_subdev。所谓的多路复用就是使用一个摄像头控制器来控制多个摄像头。比如手机上有前置和后置摄像头。

在V4L2驱动中,使用v4l2_device来表示摄像头控制器(ISP)。使用v4l2_subdev来表示具体的某一个摄像头(Sensor)。

对于手机而言 ,一般都有两个摄像头,一个前置摄像头,一个后置摄像头,其接发下图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mhEUpd9Q-1679823694000)(image/Linux之V4L2视频应用驱动/20190815164203333.png)]

在V4L2驱动中,使用v4l2_device来表示摄像头控制器

使用v4l2_subdev来表示具体的某一个摄像头的I2C控制模块,进而通过其控制摄像头

v4l2_device里有一个v4l2_subdev链表,可以选择v4l2_device去控制哪一个v4l2_subdev

v4l2框架图如下:

二、V4L2驱动主要数据结构

V4l2驱动的代码在drivers\media\v4l2-core文件夹下

  1. videobufxx_xxx.c系列文件是用于实现视频的内存分配,videobuf2_xxx系列文件是对应v4l2,而videobuf_xxx系列文件是对应于v4l(video for linux version1)。
  2. v4l2-dev.c对应于video_device的实现。
  3. v4l2-device.c对应 v4l2_device的实现。
  4. v4l2-ioctl.c对应 ioctl的实现。
  5. v4l2-subdev.c对应 42vl_subdev的实现等等。
  • struct video_device
  • video_device是个字符设备,保存管理V4l2_device设备数据。 包含底层驱动结构体v4l2_device以及为上层提供的接口cdev。
  • 应用层通过/dev/videoX的文件操作会调用video_device的v4l2_file_operations结构体中指向的函数。
  • V4L2的ioctl很复杂,应用层调用ioctl会调用到v4l2_ioctl_ops结构体中指向的函数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gCC1pW6u-1679823694002)(image/Linux之V4L2视频应用驱动/1679802252106.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ktzeoCfO-1679823694003)(image/Linux之V4L2视频应用驱动/1679802627676.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WuDmXTKr-1679823694003)(image/Linux之V4L2视频应用驱动/1679802655865.png)]

  • struct v4l2_device
    • 代表一个v4l2设备,保存设备实例的数据
    • v4l2_device中有一个链表 ,挂载着v4l2_subdev,用于管理v4l2_subdev

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5z7I4O6q-1679823694004)(image/Linux之V4L2视频应用驱动/1679801446289.png)]

  • struct v4l2_subdev
  • sub-devices子设备,代表实实在在的camera等传感器设备。驱动需要与子设备进行通信,这些子系统一般情况下就是音频处理,编解码器等,camera常见的子设备有传感器和摄像头控制器,为了方便代码管理,内核v4l2提供了一个统一的接口给这些子设备,即v4l2_sbudev结构体。
  • v4l2_subdev内有一个链表节点,可以链接至 v4l2_device。
  • v4l2_subdev有v4l2_device指针,表示属于哪个v4l2_device。
  • v4l2_subdev_ops为v4l2_subdev的具体功能实现。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cLPshbGD-1679823694005)(image/Linux之V4L2视频应用驱动/1679802947458.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J1CaZzZ5-1679823694006)(image/Linux之V4L2视频应用驱动/1679803243676.png)]

三、V4L2提供的外部接口

  • struct video_device (在v4l2-dev.h文件中)
static inline int __must_check video_register_device(struct video_device *vdev,
						     enum vfl_devnode_type type,
						     int nr)

void video_unregister_device(struct video_device *vdev);

  • **struct v4l2_device ** (在v4l2-device.h中)
int __must_check v4l2_device_register(struct device *dev,
				      struct v4l2_device *v4l2_dev);

void v4l2_device_unregister(struct v4l2_device *v4l2_dev);

  • struct v4l2_subdev (在v4l2-device.h中)
int __must_check v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
					     struct v4l2_subdev *sd);

void v4l2_device_unregister_subdev(struct v4l2_subdev *sd);

四、V4L2驱动框架模板

步骤:

  • 分配设置video_device结构体,包括.fops以及.ioctl_ops
  • 初始化v4l2_device结构体(代表一个v4l2设备)
  • 注册video_device结构体(video_device是内核对v4l2_device的官方封装,用于管理v4l2_device数据),向上层用户提供访问接口
#include <...>

static struct video_device* video_dev;
static struct v4l2_device v4l2_dev;

/* 实现各种系统调用 */
static const struct v4l2_file_operations video_dev_fops = {
.owner = THIS_MODULE,
.release = vdev_close,
.read = vdev_read,
.poll = vdev_poll,
.ioctl = video_ioctl2,
.mmap = vdev_mmap,
};

/* 实现各种系统调用 */
static const struct v4l2_ioctl_ops video_dev_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
};

static int __init video_init(void)
{
/* 分配并设置一个video_device */
video_dev = video_device_alloc();
video_dev->fops = &video_dev_fops;
video_dev->ioctl_ops = &video_dev_ioctl_ops;
video_dev->release = video_device_release;
video_dev->tvnorms = V4L2_STD_525_60;
video_dev->current_norm = V4L2_STD_NTSC_M;

<span class="token comment">/* 注册一个v4l2_device */</span>
<span class="token function">v4l2_device_register</span><span class="token punctuation">(</span>video_dev<span class="token operator">-&gt;</span>dev<span class="token punctuation">,</span> <span class="token operator">&amp;</span>v4l2_dev<span class="token punctuation">)</span><span class="token punctuation">;</span>    
video_dev<span class="token operator">-&gt;</span>v4l2_dev <span class="token operator">=</span> <span class="token operator">&amp;</span>v4l2_dev<span class="token punctuation">;</span>

<span class="token comment">/* 注册一个video_device字符设备 */</span>
<span class="token function">video_register_device</span><span class="token punctuation">(</span>video_dev<span class="token punctuation">,</span> VFL_TYPE_GRABBER<span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

}

static void __exit video_exit(void)
{
video_unregister_device(video_dev);
v4l2_device_unregister(&v4l2_dev);
video_device_release(video_dev);
}

module_init(video_init);
module_exit(video_exit);

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值