V4L2(video for linux two)
因为我也是第一次接触学习这个,这里就先当我整理笔记了。可能有些东西比较乱也会有不对的地方欢迎大家指正。主要是看关于camera相关的知识。
定义
是内核提供给应用程序访问音、视频驱动的统一接口。
工作流程
打开设备 > 检查和设置设备属性 > 设置帧格式 > 设置一种输入输出方法(缓冲区管理)> 循环获取数据 > 关闭设备
app调用v4l2框架,然后v4l2框架在调用具体的驱动
如:在APP:open > v4l2:open > driver:open
4l2提供的是一个通用的框架,然后驱动去实现具体的内容
路径linux-3.4.2/drivers/media/video/v4l2-dev.c
static const struct file_operations v4l2_fops = {
.owner = THIS_MODULE,
.read = v4l2_read,
.write = v4l2_write,
.open = v4l2_open,
.get_unmapped_area = v4l2_get_unmapped_area,
.mmap = v4l2_mmap,
.unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = v4l2_compat_ioctl32,
#endif
.release = v4l2_release,
.poll = v4l2_poll,
.llseek = no_llseek,
};
在这个文件中先看下这个file_operations v4l2_fops这个结构体,这个就是一些函数的入口
我看大部分都是从介绍结构体开始的,我也先从结构体开始看吧,看看这些结构体之间的关系。
先从video_device这个结构体开始看吧
路径:linux-3.4.2/include/media/v4l2-dev.h
struct 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;
};
struct video_device这个结构体里面主要包括以下结构体:
1.struct media_entity entity
2.struct v4l2_file_operations fops / device ops /
3.struct device / v4l device /
4.struct cdev / character device /
5.struct v4l2_device / v4l2_device parent /
6.struct v4l2_ctrl_handler
7.struct v4l2_prio_state / Priority state. If NULL, then v4l2_dev->prio will be used. /
8.struct list_head / List of struct v4l2_fh /
9.struct v4l2_ioctl_ops / ioctl callbacks */
其中有一个关于media的一个入口,看下这个关于media的结构体。
路径:linux-3.4.2/include/media/media-device.h
struct media_device {
/* dev->driver_data points to this struct. */
struct device *dev;
struct media_devnode devnode;
char model[32];
char serial[40];
char bus_info[32];
u32 hw_revision;
u32 driver_version;
u32 entity_id;
struct list_head entities;
/* Protects the entities list */
spinlock_t lock;
/* Serializes graph operations. */
struct mutex graph_mutex;
int (*link_notify)(struct media_pad *source,
struct media_pad *sink, u32 flags);
};
这个结构体暂时还不知道干嘛用的后面看代码的时候可在看起到啥作用吧
看下结构体 struct v4l2_device
路径:linux-3.4.2/include/media/v4l2-device.h
struct v4l2_device {
/* dev->driver_data points to this struct.
Note: dev might be NULL if there is no parent device
as is the case with e.g. ISA devices. */
struct device *dev;
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_device *mdev;
#endif
/* used to keep track of the registered subdevs */
struct list_head subdevs;
/* lock this struct; can be used by the driver as well if this
struct is embedded into a larger struct. */
spinlock_t lock;
/* unique device name, by default the driver name + bus ID */
char name[V4L2_DEVICE_NAME_SIZE];
/* notify callback called by some sub-devices. */
void (*notify)(struct v4l2_subdev *sd,
unsigned int notification, void *arg);
/* The control handler. May be NULL. */
struct v4l2_ctrl_handler *ctrl_handler;
/* Device's priority state */
struct v4l2_prio_state prio;
/* BKL replacement mutex. Temporary solution only. */
struct mutex ioctl_lock;
/* Keep track of the references to this struct. */
struct kref ref;
/* Release function that is called when the ref count goes to 0. */
void (*release)(struct v4l2_device *v4l2_dev);
};
struct v4l2_device这个结构体中主要包含以下结构体:
1.struct device dev / dev->driver_data points to this struct.
Note: dev might be NULL if there is no parent device
as is the case with e.g. ISA devices. /
2.struct media_device
3.struct list_head / used to keep track of the registered subdevs /
4.struct v4l2_ctrl_handler / The control handler. May be NULL. /
5.struct v4l2_prio_state / Device’s priority state */
这个结构体代表的是一个v4l2的对象,这个对象包含这个很多的子设备struct list_head subdevs 在这个子设备结构体的链表中,每一个都代表着一个子设备。
去看下这个结构体的定义,这个结构体好像是底层比较通用的一个结构。
目录:linux-3.4.2/include/linux/types.h
struct list_head {
struct list_head *next, *prev;
};
可以看出来这里面有两个结构体指针,保存着上一个节点和下一个节点的地址。所以接下来要找每个子设备的结构体的内容
目录:linux-3.4.2/include/media/v4l2-subdev.h
struct v4l2_subdev {
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity entity;
#endif
struct list_head list;
struct module *owner;
u32 flags;
struct v4l2_device *v4l2_dev;
const struct v4l2_subdev_ops *ops;
/* Never call these internal ops from within a driver! */
const struct v4l2_subdev_internal_ops *internal_ops;
/* The control handler of this subdev. May be NULL. */
struct v4l2_ctrl_handler *ctrl_handler;
/* name must be unique */
char name[V4L2_SUBDEV_NAME_SIZE];
/* can be used to group similar subdevs, value is driver-specific */
u32 grp_id;
/* pointer to private data */
void *dev_priv;
void *host_priv;
/* subdev device node */
struct video_device *devnode;
};
这个结构体中主要就是对应的一些属性以及之前都已经经常看见的哪些结构体了,就不在拆分了。
在这个框架中的运转的过程中需要对图像的缓冲去进行管理,管理这些是通过vb2_queue这个来维护的。接下来看下这个结构体。
路径:linux-3.4.2/include/media/videobuf2-core.h
/**
* struct vb2_queue - a videobuf queue
*
* @type: queue type (see V4L2_BUF_TYPE_* in linux/videodev2.h
* @io_modes: supported io methods (see vb2_io_modes enum)
* @io_flags: additional io flags (see vb2_fileio_flags enum)
* @ops: driver-specific callbacks
* @mem_ops: memory allocator specific callbacks
* @drv_priv: driver private data
* @buf_struct_size: size of the driver-specific buffer structure;
* "0" indicates the driver doesn't want to use a custom buffer
* structure type, so sizeof(struct vb2_buffer) will is used
*
* @memory: current memory type used
* @bufs: videobuf buffer structures
* @num_buffers: number of allocated/used buffers
* @queued_list: list of buffers currently queued from userspace
* @queued_count: number of buffers owned by the driver
* @done_list: list of buffers ready to be dequeued to userspace
* @done_lock: lock to protect done_list list
* @done_wq: waitqueue for processes waiting for buffers ready to be dequeued
* @alloc_ctx: memory type/allocator-specific contexts for each plane
* @streaming: current streaming state
* @fileio: file io emulator internal data, used only if emulator is active
*/
struct vb2_queue {
enum v4l2_buf_type type;
unsigned int io_modes;
unsigned int io_flags;
const struct vb2_ops *ops;
const struct vb2_mem_ops *mem_ops;
void *drv_priv;
unsigned int buf_struct_size;
/* private: internal use only */
enum v4l2_memory memory;
struct vb2_buffer *bufs[VIDEO_MAX_FRAME];
unsigned int num_buffers;
struct list_head queued_list;
atomic_t queued_count;
struct list_head done_list;
spinlock_t done_lock;
wait_queue_head_t done_wq;
void *alloc_ctx[VIDEO_MAX_PLANES];
unsigned int plane_sizes[VIDEO_MAX_PLANES];
unsigned int streaming:1;
struct vb2_fileio_data *fileio;
};
这里面有个枚举,看看枚举中有哪些type
enum v4l2_buf_type {
V4L2_BUF_TYPE_VIDEO_CAPTURE = 1,
V4L2_BUF_TYPE_VIDEO_OUTPUT = 2,
V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
V4L2_BUF_TYPE_VBI_CAPTURE = 4,
V4L2_BUF_TYPE_VBI_OUTPUT = 5,
V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6,
V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7,
#if 1
/* Experimental */
V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
#endif
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE = 10,
V4L2_BUF_TYPE_PRIVATE = 0x80,
};
我把其中我觉得重要的一些结构展开看下吧
其中有一些操作的函数的一个结构体vb2_ops看下
路径:linux-3.4.2/include/media/videobuf2-core.h
/**
* struct vb2_ops - driver-specific callbacks
*
* @queue_setup: called from VIDIOC_REQBUFS and VIDIOC_CREATE_BUFS
* handlers before memory allocation, or, if
* *num_planes != 0, after the allocation to verify a
* smaller number of buffers. Driver should return
* the required number of buffers in *num_buffers, the
* required number of planes per buffer in *num_planes; the
* size of each plane should be set in the sizes[] array
* and optional per-plane allocator specific context in the
* alloc_ctxs[] array. When called from VIDIOC_REQBUFS,
* fmt == NULL, the driver has to use the currently
* configured format and *num_buffers is the total number
* of buffers, that are being allocated. When called from
* VIDIOC_CREATE_BUFS, fmt != NULL and it describes the
* target frame format. In this case *num_buffers are being
* allocated additionally to q->num_buffers.
* @wait_prepare: release any locks taken while calling vb2 functions;
* it is called before an ioctl needs to wait for a new
* buffer to arrive; required to avoid a deadlock in
* blocking access type
* @wait_finish: reacquire all locks released in the previous callback;
* required to continue operation after sleeping while
* waiting for a new buffer to arrive
* @buf_init: called once after allocating a buffer (in MMAP case)
* or after acquiring a new USERPTR buffer; drivers may
* perform additional buffer-related initialization;
* initialization failure (return != 0) will prevent
* queue setup from completing successfully; optional
* @buf_prepare: called every time the buffer is queued from userspace
* and from the VIDIOC_PREPARE_BUF ioctl; drivers may
* perform any initialization required before each hardware
* operation in this callback; if an error is returned, the
* buffer will not be queued in driver; optional
* @buf_finish: called before every dequeue of the buffer back to
* userspace; drivers may perform any operations required
* before userspace accesses the buffer; optional
* @buf_cleanup: called once before the buffer is freed; drivers may
* perform any additional cleanup; optional
* @start_streaming: called once to enter 'streaming' state; the driver may
* receive buffers with @buf_queue callback before
* @start_streaming is called; the driver gets the number
* of already queued buffers in count parameter; driver
* can return an error if hardware fails or not enough
* buffers has been queued, in such case all buffers that
* have been already given by the @buf_queue callback are
* invalidated.
* @stop_streaming: called when 'streaming' state must be disabled; driver
* should stop any DMA transactions or wait until they
* finish and give back all buffers it got from buf_queue()
* callback; may use vb2_wait_for_all_buffers() function
* @buf_queue: passes buffer vb to the driver; driver may start
* hardware operation on this buffer; driver should give
* the buffer back by calling vb2_buffer_done() function;
* it is allways called after calling STREAMON ioctl;
* might be called before start_streaming callback if user
* pre-queued buffers before calling STREAMON
*/
struct vb2_ops {
int (*queue_setup)(struct vb2_queue *q, const struct v4l2_format *fmt,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[]);
void (*wait_prepare)(struct vb2_queue *q);
void (*wait_finish)(struct vb2_queue *q);
int (*buf_init)(struct vb2_buffer *vb);
int (*buf_prepare)(struct vb2_buffer *vb);
int (*buf_finish)(struct vb2_buffer *vb);
void (*buf_cleanup)(struct vb2_buffer *vb);
int (*start_streaming)(struct vb2_queue *q, unsigned int count);
int (*stop_streaming)(struct vb2_queue *q);
void (*buf_queue)(struct vb2_buffer *vb);
};
这里管理的成员是对应的buffer
路径:linux-3.4.2/include/media/videobuf2-core.h
/**
* struct vb2_buffer - represents a video buffer
* @v4l2_buf: struct v4l2_buffer associated with this buffer; can
* be read by the driver and relevant entries can be
* changed by the driver in case of CAPTURE types
* (such as timestamp)
* @v4l2_planes: struct v4l2_planes associated with this buffer; can
* be read by the driver and relevant entries can be
* changed by the driver in case of CAPTURE types
* (such as bytesused); NOTE that even for single-planar
* types, the v4l2_planes[0] struct should be used
* instead of v4l2_buf for filling bytesused - drivers
* should use the vb2_set_plane_payload() function for that
* @vb2_queue: the queue to which this driver belongs
* @num_planes: number of planes in the buffer
* on an internal driver queue
* @state: current buffer state; do not change
* @queued_entry: entry on the queued buffers list, which holds all
* buffers queued from userspace
* @done_entry: entry on the list that stores all buffers ready to
* be dequeued to userspace
* @planes: private per-plane information; do not change
*/
struct vb2_buffer {
struct v4l2_buffer v4l2_buf;
struct v4l2_plane v4l2_planes[VIDEO_MAX_PLANES];
struct vb2_queue *vb2_queue;
unsigned int num_planes;
/* Private: internal use only */
enum vb2_buffer_state state;
struct list_head queued_entry;
struct list_head done_entry;
struct vb2_plane planes[VIDEO_MAX_PLANES];
};
看下struct v4l2_buffer 这个结构体
路径:linux-3.4.2/include/linux/videodev2.h
/**
* struct v4l2_buffer - video buffer info
* @index: id number of the buffer
* @type: buffer type (type == *_MPLANE for multiplanar buffers)
* @bytesused: number of bytes occupied by data in the buffer (payload);
* unused (set to 0) for multiplanar buffers
* @flags: buffer informational flags
* @field: field order of the image in the buffer
* @timestamp: frame timestamp
* @timecode: frame timecode
* @sequence: sequence count of this frame
* @memory: the method, in which the actual video data is passed
* @offset: for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP;
* offset from the start of the device memory for this plane,
* (or a "cookie" that should be passed to mmap() as offset)
* @userptr: for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR;
* a userspace pointer pointing to this buffer
* @planes: for multiplanar buffers; userspace pointer to the array of plane
* info structs for this buffer
* @length: size in bytes of the buffer (NOT its payload) for single-plane
* buffers (when type != *_MPLANE); number of elements in the
* planes array for multi-plane buffers
* @input: input number from which the video data has has been captured
*
* Contains data exchanged by application and driver using one of the Streaming
* I/O methods.
*/
struct v4l2_buffer {
__u32 index;
enum v4l2_buf_type type;
__u32 bytesused;
__u32 flags;
enum v4l2_field field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
/* memory location */
enum v4l2_memory memory;
union {
__u32 offset;
unsigned long userptr;
struct v4l2_plane *planes;
} m;
__u32 length;
__u32 input;
__u32 reserved;
};
看下buffer有哪些状态
路径:linux-3.4.2/include/media/videobuf2-core.h
/**
* enum vb2_buffer_state - current video buffer state
* @VB2_BUF_STATE_DEQUEUED: buffer under userspace control
* @VB2_BUF_STATE_PREPARED: buffer prepared in videobuf and by the driver
* @VB2_BUF_STATE_QUEUED: buffer queued in videobuf, but not in driver
* @VB2_BUF_STATE_ACTIVE: buffer queued in driver and possibly used
* in a hardware operation
* @VB2_BUF_STATE_DONE: buffer returned from driver to videobuf, but
* not yet dequeued to userspace
* @VB2_BUF_STATE_ERROR: same as above, but the operation on the buffer
* has ended with an error, which will be reported
* to the userspace when it is dequeued
*/
enum vb2_buffer_state {
VB2_BUF_STATE_DEQUEUED,
VB2_BUF_STATE_PREPARED,
VB2_BUF_STATE_QUEUED,
VB2_BUF_STATE_ACTIVE,
VB2_BUF_STATE_DONE,
VB2_BUF_STATE_ERROR,
};
大概的主要就是这些结构,因为比较仓促写的也比较粗糙,等到后面找机会在回来整理以下。
接下来应该会分析一些接口,看下主要的功能。加油