V4l2是Linux用来处理视频的一个子框架。
先来看下v4l2 子框架的几个重要级别的结构体:
struct v4l2_device: 一个摄像头硬件设备可能包含多个子设备,而 v4l2_device 则是所有设备的根,负责管理所有设备, 这个结构体可以看做是所有设备和子设备的基类。
struct v4l2_device {
struct device *dev; // V4l2的父 struct device
struct media_device *mdev; // 指向 V4l2 设备所属的 media_device 对象,主要处理媒体控制框架
struct list_head subdevs; // 子设备列表
spinlock_t lock; // 锁
char name[V4L2_DEVICE_NAME_SIZE]; // 这个 V4l2 设备的唯一名称,
void (*notify)(struct v4l2_subdev *sd,
unsigned int notification, void *arg); // 由子设备调用以向此 V4L2 设备通知某些事件
struct v4l2_ctrl_handler *ctrl_handler; // 关联的控件处理程序,可以用来跟踪此V4l2 设备具有的所有控件,不需要则设置为NULL。
struct v4l2_prio_state prio; // 设备的优先级状态
struct kref ref; // 核心内部用于引用(reference) 计数
void (*release)(struct v4l2_device *v4l2_dev); // 改结构体的最后一个用户关闭时要调用的回调函数
};
==》 dev 参数通常是桥接总线相关设备数据结构的结构体: pci_dev 、 usb_device 或 platform_device。
==》 如果 dev->driver_data 字段为NULL,则此函数将使其指定正在注册的实际 V4l2_dev对象。如果V4l2->name 为空,那么将由 dev driver name + dev device name 连接产生的值。
=》 如果 dev 参数为NULL, 则必须在调用 v4l2_device_register() 之前设置 v4l2_dev ->name。
struct video_device: 这个结构体的主要目的就是提供众所周知的 /dev/videoX 和 /dev/v4l_subdevX 的设备节点。-- 桥接驱动程序结构体
struct video_device
{
#if defined(CONFIG_MEDIA_CONTROLLER) // entity、 intf_node 和 pipe 是媒体框架集成的一部分。
struct media_entity entity; // entity 可从媒体框架内部抽象出视频设备(成为一个实体)
struct media_intf_devnode *intf_devnode; // intf_node 代表媒体接口设备节点
struct media_pipeline pipe; // pipe 则代表实体所属的流管道
#endif
const struct v4l2_file_operations *fops; // 代表视频设备文件节点的文件操作。V4L2 核心可使用子系统所需要的一些额外逻辑来覆盖虚拟设备文件操作。
u32 device_caps; // v4l2_capabilities 中使用的设备功能
/* sysfs */
struct device dev; //
struct cdev *cdev; // 字符设备结构体,抽象了底层/dev/videoX 文件节点
struct v4l2_device *v4l2_dev; // 内嵌的v4l2_device 结构体
struct device *dev_parent; // 该设备的父设备,未设置使用 Vdev->v4l2_dev->dev
struct v4l2_ctrl_handler *ctrl_handler; // 默认值 vdev->v4l2_dev->ctrl_handler
struct vb2_queue *queue; // 与此设备节点关联的缓冲区管理队列,但可能是NULL, 尤其是子设备驱动程序
struct v4l2_prio_state *prio; // 指向设备优先级状态,设为NULL, 则继承 V4l2_dev->prio
/* device info */
char name[32]; // 视频设备名称
enum vfl_devnode_type vfl_type; // V4L 设备的类型
/*
enum vfl_devnode_type {
VFL_TYPE_GRABBER = 0, // 用于视频输入、输出设备
VFL_TYPE_VBI, // 用于垂直空白间隙(VBI)数据(未解码)
VFL_TYPE_RADIO, // 无线电卡
VFL_TYPE_SUBDEV, // V4l2 子设备
VFL_TYPE_SDR, // 软件定义无线电
VFL_TYPE_TOUCH, // 触摸传感器
VFL_TYPE_MAX /* Shall be the last one */
};
*/
enum vfl_devnode_direction vfl_dir; // V4l 接收器、发送器或者内存到内存(m2m / mem2mem)
/*
enum vfl_devnode_direction {
VFL_DIR_RX, // 用于采集设备
VFL_DIR_TX, // 输出设备
VFL_DIR_M2M, // 内存到内存
};
*/
int minor; // 设备节点“minor”。如果注册失败,则设置为-1
u16 num; // 核心分配的实际设备节点索引,对应得是/dev/videoX 中的 X
unsigned long flags; // 视频设备标志, 通常使用位操作设置、清除、测试标志,用的是
/*
enum v4l2_video_device_flags {
V4L2_FL_REGISTERED = 0, // 表示设备处于测试状态,无法正常使用
V4L2_FL_USES_V4L2_FH = 1, // 表示设备已经就绪,可以正常使用
};
*/
int index; // 用于区分一个物理设备上的多个索引的属性
/* V4L2 file handles */
spinlock_t fh_lock; // 自旋锁
struct list_head fh_list; // 主要用来跟踪此视频设备打开的文件处理程序的数量
int dev_debug;
v4l2_std_id tvnorms;
/* callbacks */
void (*release)(struct video_device *vdev); // 设备的最后一个用户退出是调用,不能为NULL··
const struct v4l2_ioctl_ops *ioctl_ops; // 定义一组输入输出控件(iotcl)回调函数
DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
struct mutex *lock;
};
struct vb2_queue : 视频驱动程序中的主要数据结构体,与 struct vb2_v4l_buffer 一起作用于数据流的实际逻辑和 DMA 操作的中心部分。
struct vb2_queue {
unsigned int type;8
unsigned int io_modes;
struct device *dev;
unsigned long dma_attrs;
unsigned bidirectional:1;
unsigned fileio_read_once:1;
unsigned fileio_write_immediately:1;
unsigned allow_zero_bytesused:1;
unsigned quirk_poll_must_check_waiting_for_buffers:1;
struct mutex *lock;
void *owner;
const struct vb2_ops *ops;
const struct vb2_mem_ops *mem_ops;
const struct vb2_buf_ops *buf_ops;
void *drv_priv;
unsigned int buf_struct_size;
u32 timestamp_flags;
gfp_t gfp_flags;
u32 min_buffers_needed;
struct device *alloc_devs[VB2_MAX_PLANES];
/* private: internal use only */
struct mutex mmap_lock;
unsigned int memory;
enum dma_data_direction dma_dir;
struct vb2_buffer *bufs[VB2_MAX_FRAME];
unsigned int num_buffers;
struct list_head queued_list;
unsigned int queued_count;
atomic_t owned_by_drv_count;
struct list_head done_list;
spinlock_t done_lock;
wait_queue_head_t done_wq;
unsigned int streaming:1;
unsigned int start_streaming_called:1;
unsigned int error:1;
unsigned int waiting_for_buffers:1;
unsigned int is_multiplanar:1;
unsigned int is_output:1;
unsigned int copy_timestamp:1;
unsigned int last_buffer_dequeued:1;
struct vb2_fileio_data *fileio;
struct vb2_threadio_data *threadio;
#ifdef CONFIG_VIDEO_ADV_DEBUG
/*
* Counters for how often these queue-related ops are
* called. Used to check for unbalanced ops.
*/
u32 cnt_queue_setup;
u32 cnt_wait_prepare;
u32 cnt_wait_finish;
u32 cnt_start_streaming;
u32 cnt_stop_streaming;
#endif
};
struct v4l2_subdev : 这是负责SOC 的视频系统中实现特定功能和抽象特定功能的子设备(ISP、3A 等)。
struct v4l2_subdev {
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity entity;
#endif
struct list_head list;
struct module *owner;
bool owner_v4l2_dev;
u32 flags;
struct v4l2_device *v4l2_dev;
const struct v4l2_subdev_ops *ops;
const struct v4l2_subdev_internal_ops *internal_ops;
struct v4l2_ctrl_handler *ctrl_handler;
char name[V4L2_SUBDEV_NAME_SIZE];
u32 grp_id;
void *dev_priv;
void *host_priv;
struct video_device *devnode;
struct device *dev;
struct fwnode_handle *fwnode;
struct list_head async_list;
struct v4l2_async_subdev *asd;
struct v4l2_async_notifier *notifier;
struct v4l2_async_notifier *subdev_notifier;
struct v4l2_subdev_platform_data *pdata;
};