虚拟摄像头驱动程序框架分析
摄像头驱动程序可以归类为字符设备驱动程,所以摄像头的驱动程序可以根据字符设备驱动程序的框架来完成,由于摄像头驱动程序比较复杂,所以采用分层的框架来实现。
一、字符驱动程序的实现步骤:
1、申请device结构体
2、设置device结构体
3、注册device结构体
二、由此我们可以根据上面的步骤来实现虚拟摄像头的驱动程:
1、通过video_device_alloc函数分配一个video_device结构体
2、设置video_device结构体,后面详细介绍这个结构体关键的内容
3、通知video_register_device函数注册video_device结构体
我们来分析下video_device_alloc函数:
{
return kzalloc(sizeof(struct video_device), GFP_KERNEL);
}
这个函数比较简单,其实就是分配一个结构。Kzalloc很kmalloc的区别就是Kzalloc分配机构体后并且把它初始化为0。
再看一看video_device结构体的主要内容如下:
{
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity entity;
#endif
/* device ops */
const struct v4l2_file_operations *fops;
/* sysfs */
struct device dev; /* v4l device */
struct cdev *cdev; /* character device */
/* Set either parent or v4l2_dev if your driver uses v4l2_device */
struct device *parent; /* device parent */
struct v4l2_device *v4l2_dev; /* v4l2_device parent */
/* Control handler associated with this device node. May be NULL. */
struct v4l2_ctrl_handler *ctrl_handler;
/* Priority state. If NULL, then v4l2_dev->prio will be used. */
struct v4l2_prio_state *prio;
/* device info */
char name[32];
int vfl_type;
/* 'minor' is set to -1 if the registration failed */
int minor;
u16 num;
/* use bitops to set/clear/test flags */
unsigned long flags;
/* attribute to differentiate multiple indices on one physical device */
int index;
/* V4L2 file handles */
spinlock_t fh_lock; /* Lock for all v4l2_fhs */
struct list_head fh_list; /* List of struct v4l2_fh */
int debug; /* Activates debug level*/
/* Video standard vars */
v4l2_std_id tvnorms; /* Supported tv norms */
v4l2_std_id current_norm; /* Current tvnorm */
/* callbacks */
void (*release)(struct video_device *vdev);
/* ioctl callbacks */
const struct v4l2_ioctl_ops *ioctl_ops;
/* serialization lock */
struct mutex *lock;
};
其实比较重要的就是release、fops、ioctl_ops比较重要,别的我们都可以不管。Release对于我们自己写的release函数,fops对于我们自己写的v4l2_file_operations,ioctl_ops对于我们自己写的v4l2_ioctl_ops。实现v4l2_file_operations和v4l2_ioctl_ops非常重要。
三、分析v4l2_file_operations和v4l2_ioctl_ops结构体
v4l2_file_operations结构体包含的内容如下:
struct module *owner;
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*ioctl) (struct file *, unsigned int, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
#ifdef CONFIG_COMPAT
long (*compat_ioctl32) (struct file *, unsigned int, unsigned long);
#endif
unsigned long (*get_unmapped_area) (struct file *, unsigned long,
unsigned long, unsigned long, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct file *);
int (*release) (struct file *);
};
然后这里面需要我们自己去填充的内容如下:
Owner、open、release、mmap、ioctl、poll 可以参考vivi.c里面的函数去实现
v4l2_ioctl_ops该结构体里面的函数用来设置摄像头的属性和获取摄像头的数据等,用于应用层掉用,结构体的内容如下:
/* ioctl callbacks */
/* VIDIOC_QUERYCAP handler */
int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap);
/* Priority handling */
int (*vidioc_g_priority) (struct file *file, void *fh, enum v4l2_priority *p);
int (*vidioc_s_priority) (struct file *file, void *fh, enum v4l2_priority p);
/* VIDIOC_ENUM_FMT handlers */
int (*vidioc_enum_fmt_vid_cap) (struct file *file, void *fh, struct v4l2_fmtdesc *f);
int (*vidioc_enum_fmt_vid_overlay) (struct file *file, void *fh, struct v4l2_fmtdesc *f);
int (*vidioc_enum_fmt_vid_out) (struct file *file, void *fh, struct v4l2_fmtdesc *f);
int (*vidioc_enum_fmt_vid_cap_mplane)(struct file *file, void *fh, struct v4l2_fmtdesc *f);
int (*vidioc_enum_fmt_vid_out_mplane)(struct file *file, void *fh, struct v4l2_fmtdesc *f);
int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh, struct v4l2_fmtdesc *f);
/* VIDIOC_G_FMT handlers */
int (*vidioc_g_fmt_vid_cap) (struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_g_fmt_vid_overlay)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_g_fmt_vid_out) (struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_g_fmt_vid_out_overlay)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_g_fmt_vbi_cap) (struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_g_fmt_vbi_out) (struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_g_fmt_sliced_vbi_cap)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_g_fmt_sliced_vbi_out)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_g_fmt_vid_cap_mplane)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_g_fmt_vid_out_mplane)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_g_fmt_type_private)(struct file *file, void *fh, struct v4l2_format *f);
/* VIDIOC_S_FMT handlers */
int (*vidioc_s_fmt_vid_cap) (struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_s_fmt_vid_overlay)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_s_fmt_vid_out) (struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_s_fmt_vid_out_overlay)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_s_fmt_vbi_cap) (struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_s_fmt_vbi_out) (struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_s_fmt_sliced_vbi_cap)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_s_fmt_sliced_vbi_out)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_s_fmt_vid_cap_mplane)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_s_fmt_vid_out_mplane)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_s_fmt_type_private)(struct file *file, void *fh, struct v4l2_format *f);
/* VIDIOC_TRY_FMT handlers */
int (*vidioc_try_fmt_vid_cap) (struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_try_fmt_vid_overlay)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_try_fmt_vid_out) (struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_try_fmt_vid_out_overlay)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_try_fmt_vbi_cap) (struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_try_fmt_vbi_out) (struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_try_fmt_sliced_vbi_cap)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_try_fmt_sliced_vbi_out)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_try_fmt_vid_cap_mplane)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_try_fmt_vid_out_mplane)(struct file *file, void *fh, struct v4l2_format *f);
int (*vidioc_try_fmt_type_private)(struct file *file, void *fh, struct v4l2_format *f);
/* Buffer handlers */
int (*vidioc_reqbufs) (struct file *file, void *fh, struct v4l2_requestbuffers *b);
int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b);
int (*vidioc_qbuf) (struct file *file, void *fh, struct v4l2_buffer *b);
int (*vidioc_dqbuf) (struct file *file, void *fh, struct v4l2_buffer *b);
int (*vidioc_create_bufs)(struct file *file, void *fh, struct v4l2_create_buffers *b);
int (*vidioc_prepare_buf)(struct file *file, void *fh, struct v4l2_buffer *b);
int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i);
int (*vidioc_g_fbuf) (struct file *file, void *fh, struct v4l2_framebuffer *a);
int (*vidioc_s_fbuf) (struct file *file, void *fh, struct v4l2_framebuffer *a);
/* Stream on/off */
int (*vidioc_streamon) (struct file *file, void *fh, enum v4l2_buf_type i);
int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i);
/* Standard handling
ENUMSTD is handled by videodev.c
*/
int (*vidioc_g_std) (struct file *file, void *fh, v4l2_std_id *norm);
int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id *norm);
int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a);
/* Input handling */
int (*vidioc_enum_input)(struct file *file, void *fh, struct v4l2_input *inp);
int (*vidioc_g_input) (struct file *file, void *fh, unsigned int *i);
int (*vidioc_s_input) (struct file *file, void *fh, unsigned int i);
/* Output handling */
int (*vidioc_enum_output) (struct file *file, void *fh, struct v4l2_output *a);
int (*vidioc_g_output) (struct file *file, void *fh, unsigned int *i);
int (*vidioc_s_output) (struct file *file, void *fh, unsigned int i);
/* Control handling */
int (*vidioc_queryctrl) (struct file *file, void *fh, struct v4l2_queryctrl *a);
int (*vidioc_g_ctrl) (struct file *file, void *fh, struct v4l2_control *a);
int (*vidioc_s_ctrl) (struct file *file, void *fh, struct v4l2_control *a);
int (*vidioc_g_ext_ctrls) (struct file *file, void *fh, struct v4l2_ext_controls *a);
int (*vidioc_s_ext_ctrls) (struct file *file, void *fh, struct v4l2_ext_controls *a);
int (*vidioc_try_ext_ctrls) (struct file *file, void *fh, struct v4l2_ext_controls *a);
int (*vidioc_querymenu) (struct file *file, void *fh, struct v4l2_querymenu *a);
/* Audio ioctls */
int (*vidioc_enumaudio) (struct file *file, void *fh, struct v4l2_audio *a);
int (*vidioc_g_audio) (struct file *file, void *fh, struct v4l2_audio *a);
int (*vidioc_s_audio) (struct file *file, void *fh, struct v4l2_audio *a);
/* Audio out ioctls */
int (*vidioc_enumaudout) (struct file *file, void *fh, struct v4l2_audioout *a);
int (*vidioc_g_audout) (struct file *file, void *fh, struct v4l2_audioout *a);
int (*vidioc_s_audout) (struct file *file, void *fh, struct v4l2_audioout *a);
int (*vidioc_g_modulator) (struct file *file, void *fh, struct v4l2_modulator *a);
int (*vidioc_s_modulator) (struct file *file, void *fh, struct v4l2_modulator *a);
/* Crop ioctls */
int (*vidioc_cropcap) (struct file *file, void *fh, struct v4l2_cropcap *a);
int (*vidioc_g_crop) (struct file *file, void *fh, struct v4l2_crop *a);
int (*vidioc_s_crop) (struct file *file, void *fh, struct v4l2_crop *a);
int (*vidioc_g_selection) (struct file *file, void *fh, struct v4l2_selection *s);
int (*vidioc_s_selection) (struct file *file, void *fh, struct v4l2_selection *s);
/* Compression ioctls */
int (*vidioc_g_jpegcomp) (struct file *file, void *fh, struct v4l2_jpegcompression *a);
int (*vidioc_s_jpegcomp) (struct file *file, void *fh, struct v4l2_jpegcompression *a);
int (*vidioc_g_enc_index) (struct file *file, void *fh, struct v4l2_enc_idx *a);
int (*vidioc_encoder_cmd) (struct file *file, void *fh, struct v4l2_encoder_cmd *a);
int (*vidioc_try_encoder_cmd) (struct file *file, void *fh, struct v4l2_encoder_cmd *a);
int (*vidioc_decoder_cmd) (struct file *file, void *fh, struct v4l2_decoder_cmd *a);
int (*vidioc_try_decoder_cmd) (struct file *file, void *fh, struct v4l2_decoder_cmd *a);
/* Stream type-dependent parameter ioctls */
int (*vidioc_g_parm) (struct file *file, void *fh, struct v4l2_streamparm *a);
int (*vidioc_s_parm) (struct file *file, void *fh, struct v4l2_streamparm *a);
/* Tuner ioctls */
int (*vidioc_g_tuner) (struct file *file, void *fh, struct v4l2_tuner *a);
int (*vidioc_s_tuner) (struct file *file, void *fh, struct v4l2_tuner *a);
int (*vidioc_g_frequency) (struct file *file, void *fh, struct v4l2_frequency *a);
int (*vidioc_s_frequency) (struct file *file, void *fh, struct v4l2_frequency *a);
/* Sliced VBI cap */
int (*vidioc_g_sliced_vbi_cap) (struct file *file, void *fh, struct v4l2_sliced_vbi_cap *a);
/* Log status ioctl */
int (*vidioc_log_status) (struct file *file, void *fh);
int (*vidioc_s_hw_freq_seek) (struct file *file, void *fh, struct v4l2_hw_freq_seek *a);
/* Debugging ioctls */
#ifdef CONFIG_VIDEO_ADV_DEBUG
int (*vidioc_g_register) (struct file *file, void *fh, struct v4l2_dbg_register *reg);
int (*vidioc_s_register) (struct file *file, void *fh, struct v4l2_dbg_register *reg);
#endif
int (*vidioc_g_chip_ident) (struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip);
int (*vidioc_enum_framesizes) (struct file *file, void *fh, struct v4l2_frmsizeenum *fsize);
int (*vidioc_enum_frameintervals) (struct file *file, void *fh, struct v4l2_frmivalenum *fival);
/* DV Timings IOCTLs */
int (*vidioc_enum_dv_presets) (struct file *file, void *fh, struct v4l2_dv_enum_preset *preset);
int (*vidioc_s_dv_preset) (struct file *file, void *fh, struct v4l2_dv_preset *preset);
int (*vidioc_g_dv_preset) (struct file *file, void *fh, struct v4l2_dv_preset *preset);
int (*vidioc_query_dv_preset) (struct file *file, void *fh, struct v4l2_dv_preset *qpreset);
int (*vidioc_s_dv_timings) (struct file *file, void *fh, struct v4l2_dv_timings *timings);
int (*vidioc_g_dv_timings) (struct file *file, void *fh, struct v4l2_dv_timings *timings);
int (*vidioc_subscribe_event) (struct v4l2_fh *fh, struct v4l2_event_subscription *sub);
int (*vidioc_unsubscribe_event)(struct v4l2_fh *fh, struct v4l2_event_subscription *sub);
/* For other private ioctls */
long (*vidioc_default) (struct file *file, void *fh,
bool valid_prio, int cmd, void *arg);
};
该结构体的内容非常多,我们可以参考vivi.c的代码,选择性的实现里面必要的函数,大概需要实现的函数如下:
// 表示它是一个摄像头设备
.vidioc_querycap
/* 用于列举、获得、测试、设置摄像头的数据的格式 */
.vidioc_enum_fmt_vid_cap
.vidioc_g_fmt_vid_cap
.vidioc_try_fmt_vid_cap
.vidioc_s_fmt_vid_cap
/* 缓冲区操作: 申请/查询/放入队列/取出队列 */
.vidioc_reqbufs
.vidioc_querybuf
.vidioc_qbuf
.vidioc_dqbuf
// 启动/停止
.vidioc_streamon
.vidioc_streamoff
};
上面的函数可以参考vivi.c里面的函数去实现。
在这里虚拟摄像头的驱动程序的框架大致就是这样,后续再继续对结构体里面的内容进行详细分析。