2.2 Structure of a V4L driver
device instances
|
+-sub-device instances
|
\-V4L2 device nodes
|
\-filehandle instances
2.4 Video device
video device 用于抽象系统注册的 v4l2 /dev 设备节点,以便用户空间可以进行交互。
可以通过 video_device_alloc()
分配,也可以嵌入在更大的结构体中,这样则需要自定义 release
函数。
如果是嵌入在更大的结构体中,并且没有要释放的资源,可以使用 video_device_release_empty()
。
最后通过 video_register_device()
注册。
struct video_device {
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity entity;
struct media_intf_devnode *intf_devnode;
struct media_pipeline pipe;
#endif
const struct v4l2_file_operations *fops;
u32 device_caps;
/* sysfs */
struct device dev;
struct cdev *cdev;
struct v4l2_device *v4l2_dev;
struct device *dev_parent;
struct v4l2_ctrl_handler *ctrl_handler;
struct vb2_queue *queue;
struct v4l2_prio_state *prio;
/* device info */
char name[64];
enum vfl_devnode_type vfl_type;
enum vfl_devnode_direction vfl_dir;
int minor;
u16 num;
unsigned long flags;
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);
const struct v4l2_ioctl_ops *ioctl_ops;
DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
struct mutex *lock;
};
entity:
fops: v4l2 file operations.
device_caps: 设备支持的能力,在 videodev2.h 中定义。
dev:
cdev:
v4l2_dev: 上层的 v4l2_device 设备。
dev_parent: 上层的 device 设备,如果为 NULL 在 video_register_device 中会指向 v4l2_dev->dev
ctrl_handler: 如果为 NULL, 在 video_register_device 中会指向 v4l2_dev->ctrl_handler.
queue: 和该 device node 相关的 vb2_queue 结构体。
prio: 如果为 NULL, 在 video_register_device 中会指向 v4l2_dev->prio .
name: video device name.
vfl_type: enum vfl_devnode_type, v4l2 设备的类型,在 video_register_device 中传入。
vfl_dir: enum vfl_devnode_direction, 表示 v4l2 设备的方向,RX(capture device)/TX(output device)/M2M(mem2mem, codec).
minor: device node 次设备号。
num: video device node 的编号,/dev/videoX 的 X, 在 video_register_device 最后一个参数传入。
flags: enum v4l2_video_device_flags, 一些辅助 flags.
index: 一个物理设备对应多个 v4l2 设备节点,分别的 index. 每次调用 video_register_device() 都会增加 1.
fh_lock: 用来 lock v4l2_fhs.
fh_list: v4l2_fh 链表。
dev_debug: userspace 通过 sysfs 设置的 debug level. /sys/class/video4linux/video0/dev_debug
tvnorms: 支持的电视标准 PAL/NTSC/SECAM.
release: 释放函数。在 video_device 没有 subclass 的情况下可以使用 video_device_release().
如果 video_device subclass 或者是 static 分配的,不需要释放内存使用 video_device_release_empty().
ioctl_ops: v4l2 file ioctl operations.
valid_ioctls: 支持的 ioctrl bitmap.
lock: 用来串行化 v4l2 device 的 unlock_ioctl.
其中一些 fields 需要我们手动去初始化,包括 fops, device_caps, v4l2_dev, queue, name, vfl_dir, ioctl_ops, lock.
如果需要和 media framework 联合使用,需要初始化 entity 成员,并调用 media_entity_pads_init().
如果 v4l2 driver 使用 v4l2_ioctl_ops, 则 v4l2_file_operations 中的.unlock_ioctl 回调需要使用 video_ioctl2.
2.4.1 ioctls and locking
设置 video_device->lock 和 video_device->queue->lock 两个 mutex.
这样 v4l2 core 会自动调用 video_device->lock 和 video_device->queue->lock 来串行化 v4l2 ioctls 的执行。
video_device->queue->lock 用来单独串行化 v4l2 buffer 相关的 ioctls,这样和其他 ioctls 可以并行运行。
2.4.2 Video device registration
err = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
video_register_device() 最后一个参数是生成设备节点的编号,如果为 -1 则由内核自动分配,也可以自行指定一个编号。
不同的设备类型会生成不同的设备节点:
2.4.3 Video device debugging
往/sys/class/video4linux/<devX>/dev_debug
写入数值:
2.4.4 Video device cleanup
video_unregister_device()
, 或者使用 vb2_video_unregister_device()
。
在这之前别忘记 clean up media_entity:
media_entity_cleanup (&vdev->entity)
2.4.5 helper functions
static inline void *video_get_drvdata(struct video_device *vdev)
static inline void video_set_drvdata(struct video_device *vdev, void *data)
struct video_device *video_devdata(struct file *file)
2.4.6 functions and data structures
struct v4l2_ioctl_ops {
/* VIDIOC_QUERYCAP handler */
int (*vidioc_querycap)(struct file *file, void *fh,
struct v4l2_capability *cap)
/* VIDIOC_ENUM_FMT handlers */
int (*vidioc_enum_fmt_vid_cap)(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_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_expbuf)(struct file *file, void *fh,
struct v4l2_exportbuffer *e);
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_streamon)(struct file *file, void *fh,
enum v4l2_buf_type i);
int (*vidioc_streamoff)(struct file *file, void *fh,
enum v4l2_buf_type i);
int (*vidioc_try_fmt_vid_cap_mplane)(struct file *file, void *fh,
struct v4l2_format *f);
int (*vidioc_s_fmt_meta_cap)(struct file *file, void *fh,
struct v4l2_format *f);
long (*vidioc_default)(struct file *file, void *fh,
bool valid_prio, unsigned int cmd, void *arg);
}
vidioc_default
: private ioctls 在这里实现。
v4l2-dev.h
:
多平面的像素格式:
struct v4l2_pix_format_mplane {
__u32 width;
__u32 height;
__u32 pixelformat;
__u32 field;
__u32 colorspace;
struct v4l2_plane_pix_format plane_fmt[VIDEO_MAX_PLANES];
__u8 num_planes;
__u8 flags;
union {
__u8 ycbcr_enc;
__u8 hsv_enc;
};
__u8 quantization;
__u8 xfer_func;
}
width: 图像宽度。 height: 图像高度。 pixelformat: 像素 fourcc 格式。 field: enum v4l2_field,场序。 colorspace: enum v4l2_colorspace, 颜色空间。 plane_fmt: 每个平面具体的信息。 num_planes: 平面数量。 flags: V4L2_PIX_FMT_FLAG_XXX, 标志位。 ycbcr_enc: enum v4l2_ycbcr_encoding, yuv 色彩编码。 quantization: enum v4l2_quantization, 采样方式,full range/limited range。 xfer_func: enum v4l2_xfer_func, 色彩传输函数。
struct v4l2_plane_pix_format {
__u32 sizeimage;
__u32 bytesperline;
}
sizeimage: 平面最大包含的字节数。 bytesperline: 每个平面一行的字节数。
struct v4l2_format_info {
u32 format;
u8 pixel_enc;
u8 mem_planes;
u8 comp_planes;
u8 bpp[4];
u8 bpp_div[4];
u8 hdiv;
u8 vdiv;
u8 block_w[4];
u8 block_h[4];
};
format
: 像素格式 fourcc code。pixel_enc
: 像素编码,enum v4l2_pixel_encoding, rgb/yuv/bayer。mem_planes
: memory 平面数量,包括 alpha plane,可以有 1-4 个平面,比如 nv12, 只有一个连续的 memory 平面。comp_planes
: component 平面数量,包括 alpha plane,可以有 1-4 个平面,比如 nv12,有两个 component 平面。bpp
: 每个平面每个像素的位数。bpp_div
: 支持分数像素位数的除数。hdiv
: 水平方向的缩放因子。vdiv
: 垂直方向的缩放因子。block_w
: 每个平面每个像素的宽度。
block_h
: 每个平面每个像素的高度。
video device 相关的 APIs:
int video_register_device(struct video_device *vdev,
enum vfl_devnode_type type, int nr);
void video_unregister_device(struct video_device *vdev);
struct video_device *video_device_alloc(void);
int video_device_pipeline_start(struct video_device *vdev,
struct media_pipeline *pipe);
void video_device_pipeline_stop(struct video_device *vdev);
struct media_pipeline *video_device_pipeline(struct video_device *vdev);