V4L2驱动程序架构
来源:互联网 发布:手机淘宝怎么搜索达人 编辑:程序博客网 时间:2024/05/16 18:21
1 V4L2简介
video4linux2(V4L2)是Linux内核中关于视频设备的内核驱动,它为Linux中视频设备访问提供了通用接口,在Linux系统中,V4L2驱动的Video设备节点路径通常/dev/video/中的videoX
V4L2驱动对用户空间提供字符设备,主设备号为81,对于视频设备,其次设备号为0-63。除此之外,次设备号为64-127的Radio设备,次设备号为192-223的是Teletext设备,次设备号为224-255的是VBI设备
V4L2驱动的Video设备在用户空间通过各种ioctl调用进行控制,并且可以使用mmap进行内存映射
1.1 V4L2驱动主要使用的ioctl
命令值如下所示:
- #define VIDIO_G_FMT _IOWR('V', 4, struct v4l2_format) /*获得格式*/
- #define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format) /*设置格式*/
- #define VIDIOC_REQBUFS _IOWR('V', 8, strut v4l2_requestbuffers) /*申请内存*/
- #define VIDIOC_G_FBUF _IOW('V', 10, struct v4l2_framebuffer) /*获得Framebuffer*/
- #define VIDIOC_S_BUF _IOW('V', 11, struct v4l2_framebuffer) /*设置Framebuffer*/
- #define VIDIOC_OVERLAY _IOW('V', 14, int) /*设置Overlay*/
- #define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer) /*将内存加入队列*/
- #define VIDIOC_DQBUF _IOWR('V', 17, strut v4l2_buffer) /*从队列取出内存*/
- #define VIDIOC_STREAMON _IOW('V', 18, int) /*开始流*/
- #define VIDIOC_STREAMOFF _IOW('V', 19, int) /*停止流*/
- #define VIDIOC_G_CTRL _IOWR('V', 27, struct v4l2_control) /*得到控制*/
- #define VIDIOC_S_CTRL _IOWR('V', 28, struct v4l2_control) /*设置控制*/
#define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability) /*查询能力*/#define VIDIO_G_FMT _IOWR('V', 4, struct v4l2_format) /*获得格式*/#define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format) /*设置格式*/#define VIDIOC_REQBUFS _IOWR('V', 8, strut v4l2_requestbuffers) /*申请内存*/#define VIDIOC_G_FBUF _IOW('V', 10, struct v4l2_framebuffer) /*获得Framebuffer*/#define VIDIOC_S_BUF _IOW('V', 11, struct v4l2_framebuffer) /*设置Framebuffer*/#define VIDIOC_OVERLAY _IOW('V', 14, int) /*设置Overlay*/#define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer) /*将内存加入队列*/#define VIDIOC_DQBUF _IOWR('V', 17, strut v4l2_buffer) /*从队列取出内存*/#define VIDIOC_STREAMON _IOW('V', 18, int) /*开始流*/#define VIDIOC_STREAMOFF _IOW('V', 19, int) /*停止流*/#define VIDIOC_G_CTRL _IOWR('V', 27, struct v4l2_control) /*得到控制*/#define VIDIOC_S_CTRL _IOWR('V', 28, struct v4l2_control) /*设置控制*/---------------------------------------------------------------------
1.2 重要结构
头文件 include/linux/videodev2.h
include/media/v4l2-dev.h
V4L2驱动核心实现文件:driver/media/video/v4l2-dev.c
v4l2-dev.h中定义的video_device是V4L2驱动程序的核心数据结构
- struct video_device
- {
- const struct v4l2_file_operations *fops;
- struct cdev *cdev;//字符设备
- struct device *parent;//父设备
- struct v4l2_device *v4l2_dev;//父v4l2_device
- char name[32];//名称
- int vfl_type;//类型
- int minor;//次设备号
- /*释放回调*/
- void (*release)(struct video_device *vdev);
- /*ioctl回调*/
- const struct v4l2_ioctl_ops *ioctl_ops;
- }
- 常用的结构
- 参见/include/linux/videodev2.h
- 1)设备能力结构
- struct v4l2_capability
- {
- __u8 driver[16];//驱动名
- __u8 card[32];//例如Hauppauge winTV
- __u8 bus_info[32];//PCI总线信息
- __u32 version;//内核版本
- __u32 capabilities;//设备能力
- __u32 reserved[4];
- };
- 2)数据格式结构
- struct v4l2_format
- {
- enum v4l2_buf_type type;//本结构的数据类型
- };
- 3)像素格式结构
- struct v4l2_pix_format
- {
- __u32 width;//宽度
- __u32 height;//高度
- }
- 4)请求缓冲
- struct v4l2_requestbuffers
- {
- __u32 count;//缓存数量
- enum v4l2_buf_type type;//数据流类型
- }
- 5)数据流类型包括V4L2_MEMORY_MMAP和V4L2_MEMORY_USERPTR
- enum v4l2_memory{
- };
struct video_device{const struct v4l2_file_operations *fops;struct cdev *cdev;//字符设备struct device *parent;//父设备struct v4l2_device *v4l2_dev;//父v4l2_devicechar name[32];//名称int vfl_type;//类型int minor;//次设备号/*释放回调*/void (*release)(struct video_device *vdev);/*ioctl回调*/const struct v4l2_ioctl_ops *ioctl_ops;}常用的结构参见/include/linux/videodev2.h1)设备能力结构struct v4l2_capability{__u8 driver[16];//驱动名__u8 card[32];//例如Hauppauge winTV__u8 bus_info[32];//PCI总线信息__u32 version;//内核版本__u32 capabilities;//设备能力__u32 reserved[4];};2)数据格式结构struct v4l2_format{enum v4l2_buf_type type;//本结构的数据类型};3)像素格式结构struct v4l2_pix_format{__u32width;//宽度__u32height;//高度}4)请求缓冲struct v4l2_requestbuffers{__u32count;//缓存数量enum v4l2_buf_type type;//数据流类型}5)数据流类型包括V4L2_MEMORY_MMAP和V4L2_MEMORY_USERPTRenum v4l2_memory{};
2 V4L2驱动注册
2.1 video_register_device
video4linux2驱动程序的注册drivers/media/video
video_register_device函数用来注册一个v4l驱动程序
- int video_register_device(struct video_device *vdev, int type, int nr)
- {
- return __video_register_device(vdev, type, nr, 1);
- }
- 其中参数type支持的类型如下
- #define VFL_TYPE_GRABBER 0//视频
- #define VFL_TYPE_VBI 1//从视频消隐的时间取得信息的设备
- #define VFL_TYPE_RADIO 2 //广播
- #define VFL_TYPE_VTX 3//视传设备
- #define VFL_TYPE_MAX 4//最大值
- ----------------->返回调用 __video_register_device()
- __video_register_device 函数先检查设备类型,接下来
- 寻找一个可用的子设备号,最后注册相应的字符设备
- static int __video_register_device(struct video_device *vdev, int type, int nr, int warn_if_nr_in_use)
- {
- switch (type) {
- case VFL_TYPE_GRABBER:
- minor_offset = 0;
- minor_cnt = 64;
- break;
- case VFL_TYPE_RADIO:
- minor_offset = 64;
- minor_cnt = 64;
- break;
- case VFL_TYPE_VTX:
- minor_offset = 192;
- minor_cnt = 32;
- break;
- case VFL_TYPE_VBI:
- minor_offset = 224;
- minor_cnt = 32;
- break;
- nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
- }
- nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
- vdev->cdev->ops = &v4l2_fops;
- //注册字符设备
- ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
- ret = device_register(&vdev->dev);
- //注册完毕设备信息存储在video_device数组中
- mutex_lock(&videodev_lock);
- video_device[vdev->minor] = vdev;
- mutex_unlock(&videodev_lock);
- }
int video_register_device(struct video_device *vdev, int type, int nr){return __video_register_device(vdev, type, nr, 1);}其中参数type支持的类型如下#define VFL_TYPE_GRABBER 0//视频#defineVFL_TYPE_VBI1//从视频消隐的时间取得信息的设备#define VFL_TYPE_RADIO2 //广播#define VFL_TYPE_VTX3//视传设备#defineVFL_TYPE_MAX4//最大值----------------->返回调用 __video_register_device()__video_register_device 函数先检查设备类型,接下来寻找一个可用的子设备号,最后注册相应的字符设备static int __video_register_device(struct video_device *vdev, int type, int nr, int warn_if_nr_in_use){switch (type) {case VFL_TYPE_GRABBER:minor_offset = 0;minor_cnt = 64;break;case VFL_TYPE_RADIO:minor_offset = 64;minor_cnt = 64;break;case VFL_TYPE_VTX:minor_offset = 192;minor_cnt = 32;break;case VFL_TYPE_VBI:minor_offset = 224;minor_cnt = 32;break;nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);}nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);vdev->cdev->ops = &v4l2_fops;//注册字符设备ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);ret = device_register(&vdev->dev);//注册完毕设备信息存储在video_device数组中mutex_lock(&videodev_lock);video_device[vdev->minor] = vdev;mutex_unlock(&videodev_lock);}
2.2 v4l2_fops接口
v4l2_fops为video4linux2设备提供了统一的应用层接口,v4l2_fops定义如下
- 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,
- .release = v4l2_release,
- .poll = v4l2_poll,
- .llseek = no_llseek,
- };
- v4l2_fops中的成员函数最终要调用struct video_device->fops中相应的成员
- struct video_device->fops是具体video4linux2摄像头驱动程序必须实现的接口
- static ssize_t v4l2_read(struct file *filp, char __user *buf, size_t sz, loff_t *off)
- {
- return vdev->fops->read(filp, buf, sz, off);
- }
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,.release = v4l2_release,.poll = v4l2_poll,.llseek = no_llseek,};v4l2_fops中的成员函数最终要调用struct video_device->fops中相应的成员struct video_device->fops是具体video4linux2摄像头驱动程序必须实现的接口static ssize_t v4l2_read(struct file *filp, char __user *buf, size_t sz, loff_t *off){return vdev->fops->read(filp, buf, sz, off);}
2.3 /drivers/media/video/samsung/fimc/s3c_fimc_core.c
驱动探测函数s3c_fimc_probe定义
- static int s3c_fimc_probe(struct platform_device *dev)
- {
- ctrl = s3c_fimc_register_controller(pdev);
- clk_enable(ctrl->clock);//使能时钟
- //注册V4L2驱动
- ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id);
- }
- s3c_fimc_register_contoller函数主要用来分配资源与申请中断
- static struct s3c_fimc_control *s3c_fimc_register_controller(struct platform_device *pdev)
- {
- ctrl->vd = &s3c_fimc_video_device[id];
- //申请中断
- ctrl->irq = platform_get_irq(pdev, 0);
- if(request_irq(ctrl->irq, s3c_fimc_irq, IRQF_DISABLED, ctrl->name, ctrl))
- };
- struct video_device s3c_fimc_video_device[S3C_FIMC_MAX_CTRLS] = {
- [0] = {
- .vfl_type = VID_TYPE_OVERLAY | VID_TYPE_CAPTURE | VID_TYPE_CLIPPING | VID_TYPE_SCALES,
- .fops = &s3c_fimc_fops,
- .ioctl_ops = &s3c_fimc_v4l2_ops,
- .release = s3c_fimc_vdev_release,
- .name = "sc3_video0",
- },
- }
- s3c_fimc_v4l2_ops,是在drivers/media/video/samsung/fimc中实现的v4l2_ioctl_ops,在用户空间进行ioctl等调用时,要调用到具体实现的各个函数指针
static int s3c_fimc_probe(struct platform_device *dev){ctrl = s3c_fimc_register_controller(pdev);clk_enable(ctrl->clock);//使能时钟//注册V4L2驱动ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id);}s3c_fimc_register_contoller函数主要用来分配资源与申请中断static struct s3c_fimc_control *s3c_fimc_register_controller(struct platform_device *pdev){ctrl->vd = &s3c_fimc_video_device[id];//申请中断ctrl->irq = platform_get_irq(pdev, 0);if(request_irq(ctrl->irq, s3c_fimc_irq, IRQF_DISABLED, ctrl->name, ctrl))};struct video_device s3c_fimc_video_device[S3C_FIMC_MAX_CTRLS] = {[0] = {.vfl_type = VID_TYPE_OVERLAY | VID_TYPE_CAPTURE | VID_TYPE_CLIPPING | VID_TYPE_SCALES,.fops = &s3c_fimc_fops,.ioctl_ops = &s3c_fimc_v4l2_ops,.release = s3c_fimc_vdev_release,.name = "sc3_video0",},}s3c_fimc_v4l2_ops,是在drivers/media/video/samsung/fimc中实现的v4l2_ioctl_ops,在用户空间进行ioctl等调用时,要调用到具体实现的各个函数指针
3 V4L2 操作
3.1 s3c_fimc_open
- static int s3c_fimc_open(struct file *filp)
- {
- struct s3c_fimc_control *ctrl;
- int id, ret;
- id =0;
- ctrl = &s3c_fimc.ctrl[id];
- mutex_lock(&ctrl->lock);
- if (atomic_read(&ctrl->in_use)) {
- ret = -EBUSY;
- goto resource_busy;
- } else {
- atomic_inc(&ctrl->in_use);
- s3c_fimc_reset(ctrl);
- filp->private_data = ctrl;
- }
- mutex_unlock(&ctrl->lock);
- return 0;
- resource_busy:
- mutex_unlock(&ctrl->lock);
- return ret;
- }
- 用户空间
- 打开设备文件
- fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);
static int s3c_fimc_open(struct file *filp){struct s3c_fimc_control *ctrl;int id, ret;id =0;ctrl = &s3c_fimc.ctrl[id];mutex_lock(&ctrl->lock);if (atomic_read(&ctrl->in_use)) {ret = -EBUSY;goto resource_busy;} else {atomic_inc(&ctrl->in_use);s3c_fimc_reset(ctrl);filp->private_data = ctrl;}mutex_unlock(&ctrl->lock);return 0;resource_busy:mutex_unlock(&ctrl->lock);return ret;}用户空间打开设备文件fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);
3.2 获取设备的capability,查看设备有什么功能
1)结构体
- struct v4l2_capability cap;
- ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
- /include/linux/videodev2.h
- struct v4l2_capability {
- __u8 driver[16]; /* i.e. "bttv" */
- __u8 card[32]; /* i.e. "Hauppauge WinTV" */
- __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */
- __u32 version; /* should use KERNEL_VERSION() */
- __u32 capabilities; /* Device capabilities */
- __u32 reserved[4];
- };
- 驱动实现
- static int s3c_fimc_v4l2_querycap(struct file *filp, void *fh,
- struct v4l2_capability *cap)
- {
- struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
- strcpy(cap->driver, "Samsung FIMC Driver");
- strlcpy(cap->card, ctrl->vd->name, sizeof(cap->card));
- sprintf(cap->bus_info, "FIMC AHB-bus");
- cap->version = 0;
- cap->capabilities = (V4L2_CAP_VIDEO_OVERLAY | \
- V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING);
- return 0;
- }
- 应用层调用
- static int video_capability(int fd)
- {
- int ret = 0;
- /***********get the device capability********/
- struct v4l2_capability cap;
- ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
- if (ret < 0) {
- perror("VIDIOC_QUERYCAP failed ");
- return ret;
- }
- printf("\n****Capability informations****\n");
- printf("driver: %s\n", cap.driver);
- if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
- printf("Capture capability is supported\n");
- if (cap.capabilities & V4L2_CAP_STREAMING)
- printf("Streaming capability is supported\n");
- if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
- printf("Overlay capability is supported\n");
- return 0;
- }
struct v4l2_capability cap;ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);/include/linux/videodev2.hstruct v4l2_capability {__u8driver[16];/* i.e. "bttv" */__u8card[32];/* i.e. "Hauppauge WinTV" */__u8bus_info[32];/* "PCI:" + pci_name(pci_dev) */__u32 version; /* should use KERNEL_VERSION() */__u32capabilities;/* Device capabilities */__u32reserved[4];};驱动实现static int s3c_fimc_v4l2_querycap(struct file *filp, void *fh,struct v4l2_capability *cap){struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;strcpy(cap->driver, "Samsung FIMC Driver");strlcpy(cap->card, ctrl->vd->name, sizeof(cap->card));sprintf(cap->bus_info, "FIMC AHB-bus");cap->version = 0;cap->capabilities = (V4L2_CAP_VIDEO_OVERLAY | \V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING);return 0;}应用层调用static int video_capability(int fd){int ret = 0;/***********get the device capability********/struct v4l2_capability cap;ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);if (ret < 0) {perror("VIDIOC_QUERYCAP failed ");return ret;}printf("\n****Capability informations****\n");printf("driver: %s\n", cap.driver);if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)printf("Capture capability is supported\n");if (cap.capabilities & V4L2_CAP_STREAMING) printf("Streaming capability is supported\n");if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) printf("Overlay capability is supported\n");return 0;}
3.3 选择视频输入,一个视频设备可以有多个视频输入
- 结构体
- struct v4l2_input input;
- int index;
- 得到INPUT
- ret = ioctl(fd, VIDIOC_G_INPUT, &index);
- input.index = index;
- 列举INPUT
- ret = ioctl(fd, VIDIOC_ENUMINPUT, &input);
- 设置INPUT
- ret = ioctl(fd, VIDIOC_S_INPUT, &index);
- struct v4l2_input {
- __u32 index; /* Which input */
- __u8 name[32]; /* Label */
- __u32 type; /* Type of input */
- __u32 audioset; /* Associated audios (bitfield) */
- __u32 tuner; /* Associated tuner */
- v4l2_std_id std;
- __u32 status;
- __u32 capabilities;
- __u32 reserved[3];
- };
- Ioctl: VIDIOC_S_INPUT This IOCTL takes pointer to integer containing index of the input which has to be set. Application will provide the index number as an argument.
- 0 - Composite input,
- 1 - S-Video input.
- 驱动
- static int s3c_fimc_v4l2_s_input(struct file *filp, void *fh,
- unsigned int i)
- {
- struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
- if (i >= S3C_FIMC_MAX_INPUT_TYPES)
- return -EINVAL;
- ctrl->v4l2.input = &s3c_fimc_input_types[i];
- if (s3c_fimc_input_types[i].type == V4L2_INPUT_TYPE_CAMERA)
- ctrl->in_type = PATH_IN_ITU_CAMERA;
- else
- ctrl->in_type = PATH_IN_DMA;
- return 0;
- }
- static struct v4l2_input s3c_fimc_input_types[] = {
- {
- .index = 0,
- .name = "External Camera Input",
- .type = V4L2_INPUT_TYPE_CAMERA,
- .audioset = 1,
- .tuner = 0,
- .std = V4L2_STD_PAL_BG | V4L2_STD_NTSC_M,
- .status = 0,
- },
- {
- .index = 1,
- .name = "Memory Input",
- .type = V4L2_INPUT_TYPE_MEMORY,
- .audioset = 2,
- .tuner = 0,
- .std = V4L2_STD_PAL_BG | V4L2_STD_NTSC_M,
- .status = 0,
- }
- };
- static int s3c_fimc_v4l2_enum_input(struct file *filp, void *fh,
- struct v4l2_input *i)
- {
- if (i->index >= S3C_FIMC_MAX_INPUT_TYPES)
- return -EINVAL;
- memcpy(i, &s3c_fimc_input_types[i->index], sizeof(struct v4l2_input));
- return 0;
- }
- 应用
- static int video_input(int fd)
- {
- /***********get and set the VIDIO INPUT********/
- int ret = 0;
- struct v4l2_input input;//视频输入信息,对应命令VIDIOC_ENUMINPUT
- int index;
- index = 0; //0 - Composite input, 1 - S-Video input.
- ret = ioctl (fd, VIDIOC_S_INPUT, &index);
- if (ret < 0) {
- perror ("VIDIOC_S_INPUT");
- return ret;
- }
- input.index = index;
- ret = ioctl (fd, VIDIOC_ENUMINPUT, &input);
- if (ret < 0){
- perror ("VIDIOC_ENUMINPUT");
- return ret;
- }
- printf("\n****input informations****\n");
- printf("name of the input = %s\n", input.name);
- return 0;
- }
结构体struct v4l2_input input;int index;得到INPUTret = ioctl(fd, VIDIOC_G_INPUT, &index);input.index = index;列举INPUTret = ioctl(fd, VIDIOC_ENUMINPUT, &input);设置INPUTret = ioctl(fd, VIDIOC_S_INPUT, &index);struct v4l2_input {__u32 index;/* Which input */__u8 name[32];/* Label */__u32 type;/* Type of input */__u32 audioset;/* Associated audios (bitfield) */__u32 tuner; /* Associated tuner */v4l2_std_id std;__u32 status;__u32 capabilities;__u32 reserved[3];};Ioctl: VIDIOC_S_INPUT This IOCTL takes pointer to integer containing index of the input which has to be set. Application will provide the index number as an argument. 0 - Composite input, 1 - S-Video input.驱动static int s3c_fimc_v4l2_s_input(struct file *filp, void *fh,unsigned int i){struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;if (i >= S3C_FIMC_MAX_INPUT_TYPES)return -EINVAL;ctrl->v4l2.input = &s3c_fimc_input_types[i];if (s3c_fimc_input_types[i].type == V4L2_INPUT_TYPE_CAMERA)ctrl->in_type = PATH_IN_ITU_CAMERA;elsectrl->in_type = PATH_IN_DMA;return 0;}static struct v4l2_input s3c_fimc_input_types[] = {{.index= 0,.name= "External Camera Input",.type= V4L2_INPUT_TYPE_CAMERA,.audioset= 1,.tuner= 0,.std= V4L2_STD_PAL_BG | V4L2_STD_NTSC_M,.status= 0,}, {.index= 1,.name= "Memory Input",.type= V4L2_INPUT_TYPE_MEMORY,.audioset= 2,.tuner= 0,.std= V4L2_STD_PAL_BG | V4L2_STD_NTSC_M,.status= 0,}};static int s3c_fimc_v4l2_enum_input(struct file *filp, void *fh,struct v4l2_input *i){if (i->index >= S3C_FIMC_MAX_INPUT_TYPES)return -EINVAL;memcpy(i, &s3c_fimc_input_types[i->index], sizeof(struct v4l2_input));return 0;}应用static int video_input(int fd){/***********get and set the VIDIO INPUT********/int ret = 0;struct v4l2_input input;//视频输入信息,对应命令VIDIOC_ENUMINPUT int index;index = 0; //0 - Composite input, 1 - S-Video input. ret = ioctl (fd, VIDIOC_S_INPUT, &index);if (ret < 0) {perror ("VIDIOC_S_INPUT");return ret;}input.index = index;ret = ioctl (fd, VIDIOC_ENUMINPUT, &input);if (ret < 0){perror ("VIDIOC_ENUMINPUT");return ret;}printf("\n****input informations****\n");printf("name of the input = %s\n", input.name);return 0;}
3.4 遍历所有视频格式,查询驱动所支持的格式
- 结构
- struct v4l2_fmtdes fmtdes;
- ret = ioctl(fd, VIDIOC_ENUM_FMT, &fmtdes);
- struct v4l2_fmtdesc {
- __u32 index; /* Format number */
- enum v4l2_buf_type type; /* buffer type */
- __u32 flags;
- __u8 description[32]; /* Description string */
- __u32 pixelformat; /* Format fourcc */
- __u32 reserved[4];
- };
- 驱动
- static int s3c_fimc_v4l2_enum_fmt_vid_cap(struct file *filp, void *fh,
- struct v4l2_fmtdesc *f)
- {
- struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
- int index = f->index;
- if (index >= S3C_FIMC_MAX_CAPTURE_FORMATS)
- return -EINVAL;
- memset(f, 0, sizeof(*f));
- memcpy(f, ctrl->v4l2.fmtdesc + index, sizeof(*f));
- return 0;
- }
- #define S3C_FIMC_MAX_CAPTURE_FORMATS ARRAY_SIZE(s3c_fimc_capture_formats)
- const static struct v4l2_fmtdesc s3c_fimc_capture_formats[] = {
- {
- .index = 0,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PLANAR,
- .description = "4:2:0, planar, Y-Cb-Cr",
- .pixelformat = V4L2_PIX_FMT_YUV420,
- },
- {
- .index = 1,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PLANAR,
- .description = "4:2:2, planar, Y-Cb-Cr",
- .pixelformat = V4L2_PIX_FMT_YUV422P,
- },
- {
- .index = 2,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PACKED,
- .description = "4:2:2, packed, YCBYCR",
- .pixelformat = V4L2_PIX_FMT_YUYV,
- },
- {
- .index = 3,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = FORMAT_FLAGS_PACKED,
- .description = "4:2:2, packed, CBYCRY",
- .pixelformat = V4L2_PIX_FMT_UYVY,
- }
- };
- const static struct v4l2_fmtdesc s3c_fimc_overlay_formats[] = {
- {
- .index = 0,
- .type = V4L2_BUF_TYPE_VIDEO_OVERLAY,
- .flags = FORMAT_FLAGS_PACKED,
- .description = "16 bpp RGB, le",
- .pixelformat = V4L2_PIX_FMT_RGB565,
- },
- {
- .index = 1,
- .type = V4L2_BUF_TYPE_VIDEO_OVERLAY,
- .flags = FORMAT_FLAGS_PACKED,
- .description = "24 bpp RGB, le",
- .pixelformat = V4L2_PIX_FMT_RGB24,
- },
- };
- 应用层
- static int video_fmtdesc(int fd)
- {
- /***********Format Enumeration************/
- int ret = 0;
- struct v4l2_fmtdesc fmtdes;
- CLEAR(fmtdes);
- fmtdes.index = 0;
- fmtdes.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- printf("\n**********vidioc enumeration stream format informations:****\n");
- while (1) {
- ret = ioctl(fd, VIDIOC_ENUM_FMT, &fmtdes);
- if (ret < 0)
- break;
- printf("{ pixelformat = %c%c%c%c, description = %s }\n",
- (fmtdes.pixelformat & 0xFF),
- (fmtdes.pixelformat >> 8) & 0xFF,
- (fmtdes.pixelformat >> 16) & 0xFF,
- (fmtdes.pixelformat >> 24) & 0xFF,
- fmtdes.description);
- if (fmtdes.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- printf("video capture type:\n");
- if (fmtdes.pixelformat == V4L2_PIX_FMT_YUYV)
- printf("V4L2_PIX_FMT_YUYV\n");
- fmtdes.index++;
- }
- return 0;
- }
结构struct v4l2_fmtdes fmtdes;ret = ioctl(fd, VIDIOC_ENUM_FMT, &fmtdes);struct v4l2_fmtdesc {__u32 index; /* Format number */enum v4l2_buf_type type; /* buffer type */__u32 flags;__u8 description[32]; /* Description string */__u32 pixelformat; /* Format fourcc */__u32 reserved[4];};驱动static int s3c_fimc_v4l2_enum_fmt_vid_cap(struct file *filp, void *fh,struct v4l2_fmtdesc *f){struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;int index = f->index;if (index >= S3C_FIMC_MAX_CAPTURE_FORMATS)return -EINVAL;memset(f, 0, sizeof(*f));memcpy(f, ctrl->v4l2.fmtdesc + index, sizeof(*f));return 0;}#define S3C_FIMC_MAX_CAPTURE_FORMATSARRAY_SIZE(s3c_fimc_capture_formats)const static struct v4l2_fmtdesc s3c_fimc_capture_formats[] = {{.index= 0,.type= V4L2_BUF_TYPE_VIDEO_CAPTURE,.flags= FORMAT_FLAGS_PLANAR,.description= "4:2:0, planar, Y-Cb-Cr",.pixelformat= V4L2_PIX_FMT_YUV420,},{.index= 1,.type= V4L2_BUF_TYPE_VIDEO_CAPTURE,.flags= FORMAT_FLAGS_PLANAR,.description= "4:2:2, planar, Y-Cb-Cr",.pixelformat= V4L2_PIX_FMT_YUV422P,},{.index= 2,.type= V4L2_BUF_TYPE_VIDEO_CAPTURE,.flags= FORMAT_FLAGS_PACKED,.description= "4:2:2, packed, YCBYCR",.pixelformat= V4L2_PIX_FMT_YUYV,},{.index= 3,.type= V4L2_BUF_TYPE_VIDEO_CAPTURE,.flags= FORMAT_FLAGS_PACKED,.description= "4:2:2, packed, CBYCRY",.pixelformat= V4L2_PIX_FMT_UYVY,}};const static struct v4l2_fmtdesc s3c_fimc_overlay_formats[] = {{.index= 0,.type= V4L2_BUF_TYPE_VIDEO_OVERLAY,.flags= FORMAT_FLAGS_PACKED,.description= "16 bpp RGB, le",.pixelformat= V4L2_PIX_FMT_RGB565,},{.index= 1,.type= V4L2_BUF_TYPE_VIDEO_OVERLAY,.flags= FORMAT_FLAGS_PACKED,.description= "24 bpp RGB, le",.pixelformat= V4L2_PIX_FMT_RGB24,},};应用层static int video_fmtdesc(int fd){/***********Format Enumeration************/int ret = 0;struct v4l2_fmtdesc fmtdes;CLEAR(fmtdes);fmtdes.index = 0;fmtdes.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;printf("\n**********vidioc enumeration stream format informations:****\n");while (1) {ret = ioctl(fd, VIDIOC_ENUM_FMT, &fmtdes);if (ret < 0) break; printf("{ pixelformat = %c%c%c%c, description = %s }\n",(fmtdes.pixelformat & 0xFF),(fmtdes.pixelformat >> 8) & 0xFF,(fmtdes.pixelformat >> 16) & 0xFF, (fmtdes.pixelformat >> 24) & 0xFF,fmtdes.description);if (fmtdes.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)printf("video capture type:\n");if (fmtdes.pixelformat == V4L2_PIX_FMT_YUYV)printf("V4L2_PIX_FMT_YUYV\n");fmtdes.index++;}return 0;}
3.5 设置视频捕获格式(重要)
- 结构体
- 帧格式包括宽度和高度
- struct v4l2_format fmt;
- ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
- struct v4l2_format {
- enum v4l2_buf_type type;//数据流类型,必须是V4L2_BUF_TYPE_VIDEO_CAPTURE
- union {
- struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
- struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
- struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */
- struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
- __u8 raw_data[200]; /* user-defined */
- } fmt;
- };
- struct v4l2_pix_format {
- __u32 pixelformat;//视频数据存储类型,例如是YUV4:2:2还是RGB
- }
- 驱动
- static int s3c_fimc_v4l2_s_fmt_vid_cap(struct file *filp, void *fh,
- struct v4l2_format *f)
- {
- struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
- ctrl->v4l2.frmbuf.fmt = f->fmt.pix;
- if (f->fmt.pix.priv == V4L2_FMT_IN)
- s3c_fimc_set_input_frame(ctrl, &f->fmt.pix);
- else
- s3c_fimc_set_output_frame(ctrl, &f->fmt.pix);
- return 0;
- }
- int s3c_fimc_set_input_frame(struct s3c_fimc_control *ctrl,
- struct v4l2_pix_format *fmt)
- {
- s3c_fimc_set_input_format(ctrl, fmt);
- return 0;
- }
- static void s3c_fimc_set_input_format(struct s3c_fimc_control *ctrl,
- struct v4l2_pix_format *fmt)
- {
- struct s3c_fimc_in_frame *frame = &ctrl->in_frame;
- frame->width = fmt->width;
- frame->height = fmt->height;
- switch (fmt->pixelformat) {
- case V4L2_PIX_FMT_RGB565:
- frame->format = FORMAT_RGB565;
- frame->planes = 1;
- break;
- case V4L2_PIX_FMT_RGB24:
- frame->format = FORMAT_RGB888;
- frame->planes = 1;
- break;
- case V4L2_PIX_FMT_NV12:
- frame->format = FORMAT_YCBCR420;
- frame->planes = 2;
- frame->order_2p = LSB_CBCR;
- break;
- case V4L2_PIX_FMT_NV21:
- frame->format = FORMAT_YCBCR420;
- frame->planes = 2;
- frame->order_2p = LSB_CRCB;
- break;
- case V4L2_PIX_FMT_NV12X:
- frame->format = FORMAT_YCBCR420;
- frame->planes = 2;
- frame->order_2p = MSB_CBCR;
- break;
- case V4L2_PIX_FMT_NV21X:
- frame->format = FORMAT_YCBCR420;
- frame->planes = 2;
- frame->order_2p = MSB_CRCB;
- break;
- case V4L2_PIX_FMT_YUV420:
- frame->format = FORMAT_YCBCR420;
- frame->planes = 3;
- break;
- case V4L2_PIX_FMT_YUYV:
- frame->format = FORMAT_YCBCR422;
- frame->planes = 1;
- frame->order_1p = IN_ORDER422_YCBYCR;
- break;
- case V4L2_PIX_FMT_YVYU:
- frame->format = FORMAT_YCBCR422;
- frame->planes = 1;
- frame->order_1p = IN_ORDER422_YCRYCB;
- break;
- case V4L2_PIX_FMT_UYVY:
- frame->format = FORMAT_YCBCR422;
- frame->planes = 1;
- frame->order_1p = IN_ORDER422_CBYCRY;
- break;
- case V4L2_PIX_FMT_VYUY:
- frame->format = FORMAT_YCBCR422;
- frame->planes = 1;
- frame->order_1p = IN_ORDER422_CRYCBY;
- break;
- case V4L2_PIX_FMT_NV16:
- frame->format = FORMAT_YCBCR422;
- frame->planes = 2;
- frame->order_1p = LSB_CBCR;
- break;
- case V4L2_PIX_FMT_NV61:
- frame->format = FORMAT_YCBCR422;
- frame->planes = 2;
- frame->order_1p = LSB_CRCB;
- break;
- case V4L2_PIX_FMT_NV16X:
- frame->format = FORMAT_YCBCR422;
- frame->planes = 2;
- frame->order_1p = MSB_CBCR;
- break;
- case V4L2_PIX_FMT_NV61X:
- frame->format = FORMAT_YCBCR422;
- frame->planes = 2;
- frame->order_1p = MSB_CRCB;
- break;
- case V4L2_PIX_FMT_YUV422P:
- frame->format = FORMAT_YCBCR422;
- frame->planes = 3;
- break;
- }
- }
- 应用层
- static int video_setfmt(int fd)
- {
- /***********set Stream data format********/
- int ret = 0;
- struct v4l2_format fmt;
- CLEAR(fmt);
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = 640;
- fmt.fmt.pix.height = 480;
- fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//for PAL
- fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
- ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
- if (ret < 0) {
- perror("VIDIOC_S_FMT");
- return ret;
- }
- return 0;
- }
结构体帧格式包括宽度和高度struct v4l2_format fmt;ret = ioctl(fd, VIDIOC_S_FMT, &fmt);struct v4l2_format {enum v4l2_buf_type type;//数据流类型,必须是V4L2_BUF_TYPE_VIDEO_CAPTUREunion {struct v4l2_pix_formatpix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */struct v4l2_windowwin; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */struct v4l2_vbi_formatvbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */struct v4l2_sliced_vbi_formatsliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */__u8raw_data[200]; /* user-defined */} fmt;};struct v4l2_pix_format{__u32 pixelformat;//视频数据存储类型,例如是YUV4:2:2还是RGB}驱动static int s3c_fimc_v4l2_s_fmt_vid_cap(struct file *filp, void *fh,struct v4l2_format *f){struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;ctrl->v4l2.frmbuf.fmt = f->fmt.pix;if (f->fmt.pix.priv == V4L2_FMT_IN)s3c_fimc_set_input_frame(ctrl, &f->fmt.pix);elses3c_fimc_set_output_frame(ctrl, &f->fmt.pix);return 0;}int s3c_fimc_set_input_frame(struct s3c_fimc_control *ctrl,struct v4l2_pix_format *fmt){s3c_fimc_set_input_format(ctrl, fmt);return 0;}static void s3c_fimc_set_input_format(struct s3c_fimc_control *ctrl,struct v4l2_pix_format *fmt){struct s3c_fimc_in_frame *frame = &ctrl->in_frame;frame->width = fmt->width;frame->height = fmt->height;switch (fmt->pixelformat) {case V4L2_PIX_FMT_RGB565:frame->format = FORMAT_RGB565;frame->planes = 1;break;case V4L2_PIX_FMT_RGB24:frame->format = FORMAT_RGB888;frame->planes = 1;break;case V4L2_PIX_FMT_NV12:frame->format = FORMAT_YCBCR420;frame->planes = 2;frame->order_2p = LSB_CBCR;break;case V4L2_PIX_FMT_NV21:frame->format = FORMAT_YCBCR420;frame->planes = 2;frame->order_2p = LSB_CRCB;break;case V4L2_PIX_FMT_NV12X:frame->format = FORMAT_YCBCR420;frame->planes = 2;frame->order_2p = MSB_CBCR;break;case V4L2_PIX_FMT_NV21X:frame->format = FORMAT_YCBCR420;frame->planes = 2;frame->order_2p = MSB_CRCB;break;case V4L2_PIX_FMT_YUV420:frame->format = FORMAT_YCBCR420;frame->planes = 3;break;case V4L2_PIX_FMT_YUYV:frame->format = FORMAT_YCBCR422;frame->planes = 1;frame->order_1p = IN_ORDER422_YCBYCR;break;case V4L2_PIX_FMT_YVYU:frame->format = FORMAT_YCBCR422;frame->planes = 1;frame->order_1p = IN_ORDER422_YCRYCB;break;case V4L2_PIX_FMT_UYVY:frame->format = FORMAT_YCBCR422;frame->planes = 1;frame->order_1p = IN_ORDER422_CBYCRY;break;case V4L2_PIX_FMT_VYUY:frame->format = FORMAT_YCBCR422;frame->planes = 1;frame->order_1p = IN_ORDER422_CRYCBY;break;case V4L2_PIX_FMT_NV16:frame->format = FORMAT_YCBCR422;frame->planes = 2;frame->order_1p = LSB_CBCR;break;case V4L2_PIX_FMT_NV61:frame->format = FORMAT_YCBCR422;frame->planes = 2;frame->order_1p = LSB_CRCB;break;case V4L2_PIX_FMT_NV16X:frame->format = FORMAT_YCBCR422;frame->planes = 2;frame->order_1p = MSB_CBCR;break;case V4L2_PIX_FMT_NV61X:frame->format = FORMAT_YCBCR422;frame->planes = 2;frame->order_1p = MSB_CRCB;break;case V4L2_PIX_FMT_YUV422P:frame->format = FORMAT_YCBCR422;frame->planes = 3;break;}}应用层static int video_setfmt(int fd){ /***********set Stream data format********/ int ret = 0; struct v4l2_format fmt;CLEAR(fmt);fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;fmt.fmt.pix.width =640;fmt.fmt.pix.height = 480;fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//for PALfmt.fmt.pix.field = V4L2_FIELD_INTERLACED;ret = ioctl(fd, VIDIOC_S_FMT, &fmt);if (ret < 0) {perror("VIDIOC_S_FMT");return ret;}return 0;}
3.6 视频格式查询
在v4l2中,有两种查询视频格式的方法,一个是遍历所有视频格式的
一个是查询出一种格式的
/*查询出一种格式*/
ret = ioctl(fd, VIDIOC_G_FMT, &fmt);
/*遍历所有视频格式,查询驱动所支持的格式*/
VIDIOC_ENUM_FMT
- 驱动
- static int s3c_fimc_v4l2_g_fmt_vid_cap(struct file *filp, void *fh,
- struct v4l2_format *f)
- {
- struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
- int size = sizeof(struct v4l2_pix_format);
- memset(&f->fmt.pix, 0, size);
- memcpy(&f->fmt.pix, &(ctrl->v4l2.frmbuf.fmt), size);
- return 0;
- }
- 应用
- static int video_getfmt(int fd)
- {
- /***********get Stream data format********/
- int ret= 0;
- struct v4l2_format fmt;
- CLEAR(fmt);
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- ret = ioctl(fd, VIDIOC_G_FMT, &fmt);
- if (ret < 0) {
- perror("VIDIOC_G_FMT");
- return ret;
- }
- printf("/n**********vidioc get stream format informations:****\n");
- if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
- printf("8-bit YUYVV pixel format\n");
- printf("Size of the buffer = %d\n", fmt.fmt.pix.sizeimage);
- printf("Line offset = %d\n", fmt.fmt.pix.bytesperline);
- if (fmt.fmt.pix.field == V4L2_FIELD_INTERLACED)
- printf("Storate format is interlaced frame format\n");
- return 0;
- }
驱动static int s3c_fimc_v4l2_g_fmt_vid_cap(struct file *filp, void *fh,struct v4l2_format *f){struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;int size = sizeof(struct v4l2_pix_format);memset(&f->fmt.pix, 0, size);memcpy(&f->fmt.pix, &(ctrl->v4l2.frmbuf.fmt), size);return 0;}应用static int video_getfmt(int fd){/***********get Stream data format********/int ret= 0;struct v4l2_format fmt;CLEAR(fmt);fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;ret = ioctl(fd, VIDIOC_G_FMT, &fmt);if (ret < 0) {perror("VIDIOC_G_FMT");return ret;}printf("/n**********vidioc get stream format informations:****\n");if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)printf("8-bit YUYVV pixel format\n");printf("Size of the buffer = %d\n", fmt.fmt.pix.sizeimage);printf("Line offset = %d\n", fmt.fmt.pix.bytesperline);if (fmt.fmt.pix.field == V4L2_FIELD_INTERLACED)printf("Storate format is interlaced frame format\n");return 0;}
3.7 向驱动申请帧缓冲,内存,一般不超过5个,帧缓冲管理
- 结构体
- struct v4l2_requestbuffers req;
- ret = ioctl(fd, VIDIOC_REQBUFS, &req);
- ret = ioctl(fd, VIDIOC_QUERYBUF, &buf);//读取缓存
- struct v4l2_requestbuffers {
- __u32 count;
- enum v4l2_buf_type type;
- enum v4l2_memory memory;
- __u32 reserved[2];
- };
- 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;
- } m;
- __u32 length;
- __u32 input;
- __u32 reserved;
- };
- 使用VIDIOC_REQBUFS 我们获取了req.count个缓存,下一步通过
- 调用VIDIOC_QUERYBUF 命令来获取这些缓存的地址,然后使用
- mmap函数转换成应用程序中的绝对地址,最后把这些缓存放入
- 缓存队列。
- The main steps that the application must perform for buffer allocation are:
- Allocating Memory
- Getting Physical Address
- Mapping Kernel Space Address to User Space
- 驱动支持
- static int s3c_fimc_v4l2_reqbufs(struct file *filp, void *fh,
- struct v4l2_requestbuffers *b)
- {
- if (b->memory != V4L2_MEMORY_MMAP) {
- err("V4L2_MEMORY_MMAP is only supported\n");
- return -EINVAL;
- }
- /* control user input */
- if (b->count > 4)
- b->count = 4;
- else if (b->count < 1)
- b->count = 1;
- return 0;
- }
- static int s3c_fimc_v4l2_querybuf(struct file *filp, void *fh,
- struct v4l2_buffer *b)
- {
- struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
- if (b->type != V4L2_BUF_TYPE_VIDEO_OVERLAY && \
- b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (b->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
- b->length = ctrl->out_frame.buf_size;
- /*
- * NOTE: we use the m.offset as an index for multiple frames out.
- * Because all frames are not contiguous, we cannot use it as
- * original purpose.
- * The index value used to find out which frame user wants to mmap.
- */
- b->m.offset = b->index * PAGE_SIZE;
- return 0;
- }
- static int s3c_fimc_v4l2_qbuf(struct file *filp, void *fh,
- struct v4l2_buffer *b)
- {
- return 0;
- }
- 应用层
- static int video_mmap(int fd)
- {
- /*******step 1*****requestbuffers Allocating Memory *******/
- int ret = 0;
- struct v4l2_requestbuffers req;
- CLEAR(req);
- req.count = 4;
- req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- req.memory = V4L2_MEMORY_MMAP;
- ret = ioctl(fd, VIDIOC_REQBUFS, &req);
- if (ret < 0) {
- perror("VIDIOC_REQBUFS");
- return ret;
- }
- if (req.count < 2)
- printf("insufficient buffer memory\n");
- printf("Number of buffers allocated = %d\n", req.count);
- /*******step 2*****Getting Physical Address *******/
- buffers = calloc(req.count, sizeof(*buffers));
- for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
- {
- struct v4l2_buffer buf;//驱动中的一帧
- CLEAR(buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- buf.index = n_buffers;
- ret = ioctl(fd, VIDIOC_QUERYBUF, &buf);
- if (ret < 0) {
- perror("VIDIOC_QUERYBUF");
- return ret;
- }
- /*******step 3*****Mapping Kernel Space Address to User Space*******/
- buffers[n_buffers].length = buf.length;
- buffers[n_buffers].start =
- mmap(NULL,
- buf.length,
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- fd,
- buf.m.offset);
- //if (MAP_FAILED == buffers[n_buffers].start)
- //perror("mmap failed \n");
- }
- /************requestbuffers in queue***********/
- for (i = 0; i < n_buffers; ++i) {
- struct v4l2_buffer buf;
- CLEAR(buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- buf.index = i;
- ret = ioctl(fd, VIDIOC_QBUF, &buf);//申请的缓冲进入队列
- if (ret < 0) {
- perror("VIDIOC_QBUF");
- return ret;
- }
- }
- return 0;
- }
结构体struct v4l2_requestbuffers req;ret = ioctl(fd, VIDIOC_REQBUFS, &req);ret = ioctl(fd, VIDIOC_QUERYBUF, &buf);//读取缓存struct v4l2_requestbuffers {__u32count;enum v4l2_buf_type type;enum v4l2_memory memory;__u32reserved[2];};struct v4l2_buffer {__u32index;enum v4l2_buf_type type;__u32bytesused;__u32flags;enum v4l2_fieldfield;struct timevaltimestamp;struct v4l2_timecodetimecode;__u32sequence;/* memory location */enum v4l2_memory memory;union {__u32 offset;unsigned long userptr;} m;__u32length;__u32input;__u32reserved;};使用VIDIOC_REQBUFS 我们获取了req.count个缓存,下一步通过调用VIDIOC_QUERYBUF 命令来获取这些缓存的地址,然后使用mmap函数转换成应用程序中的绝对地址,最后把这些缓存放入缓存队列。The main steps that the application must perform for buffer allocation are: Allocating Memory Getting Physical Address Mapping Kernel Space Address to User Space 驱动支持static int s3c_fimc_v4l2_reqbufs(struct file *filp, void *fh,struct v4l2_requestbuffers *b){if (b->memory != V4L2_MEMORY_MMAP) {err("V4L2_MEMORY_MMAP is only supported\n");return -EINVAL;}/* control user input */if (b->count > 4)b->count = 4;else if (b->count < 1)b->count = 1;return 0;}static int s3c_fimc_v4l2_querybuf(struct file *filp, void *fh,struct v4l2_buffer *b){struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;if (b->type != V4L2_BUF_TYPE_VIDEO_OVERLAY && \b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)return -EINVAL;if (b->memory != V4L2_MEMORY_MMAP)return -EINVAL;b->length = ctrl->out_frame.buf_size;/* * NOTE: we use the m.offset as an index for multiple frames out. * Because all frames are not contiguous, we cannot use it as * original purpose. * The index value used to find out which frame user wants to mmap. */b->m.offset = b->index * PAGE_SIZE;return 0;}static int s3c_fimc_v4l2_qbuf(struct file *filp, void *fh,struct v4l2_buffer *b){return 0;}应用层static int video_mmap(int fd){/*******step 1*****requestbuffers Allocating Memory *******/int ret = 0;struct v4l2_requestbuffers req;CLEAR(req);req.count = 4;req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;req.memory = V4L2_MEMORY_MMAP;ret = ioctl(fd, VIDIOC_REQBUFS, &req);if (ret < 0) {perror("VIDIOC_REQBUFS");return ret;}if (req.count < 2)printf("insufficient buffer memory\n");printf("Number of buffers allocated = %d\n", req.count);/*******step 2*****Getting Physical Address *******/buffers = calloc(req.count, sizeof(*buffers));for (n_buffers = 0; n_buffers < req.count; ++n_buffers){struct v4l2_buffer buf;//驱动中的一帧CLEAR(buf);buf.type= V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;buf.index= n_buffers;ret = ioctl(fd, VIDIOC_QUERYBUF, &buf);if (ret < 0) {perror("VIDIOC_QUERYBUF");return ret;}/*******step 3*****Mapping Kernel Space Address to User Space*******/buffers[n_buffers].length = buf.length;buffers[n_buffers].start = mmap(NULL,buf.length,PROT_READ | PROT_WRITE,MAP_SHARED,fd,buf.m.offset);//if (MAP_FAILED == buffers[n_buffers].start)//perror("mmap failed \n");}/************requestbuffers in queue***********/for (i = 0; i < n_buffers; ++i) {struct v4l2_buffer buf;CLEAR(buf);buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory= V4L2_MEMORY_MMAP;buf.index = i;ret = ioctl(fd, VIDIOC_QBUF, &buf);//申请的缓冲进入队列if (ret < 0) {perror("VIDIOC_QBUF");return ret;}}return 0;}
3.8 开始捕捉图像数据(重要)
- <PRE class=csharp name="code" sizcache="2" sizset="15"><P>结构体</P><PRE class=csharp name="code">enum v4l2_buf_type type;//开始捕捉图像数据
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- ret = ioctl(fd, VIDIOC_STREAMON, &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_PRIVATE = 0x80,
- };
- 驱动
- static int s3c_fimc_v4l2_streamon(struct file *filp, void *fh,
- enum v4l2_buf_type i)
- {
- struct s3c_fimc_control *ctrl = (struct s3c_fimc_control *) fh;
- if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- printk("s3c_fimc_v4l2_streamon is called\n");
- if (ctrl->in_type != PATH_IN_DMA)
- s3c_fimc_init_camera(ctrl);
- ctrl->out_frame.skip_frames = 0;
- FSET_CAPTURE(ctrl);
- FSET_IRQ_NORMAL(ctrl);
- s3c_fimc_start_dma(ctrl);
- return 0;
- }
- 硬件控制寄存器的配置
- 应用层
- static int video_streamon(int fd)
- {
- int ret = 0;
- /************start stream on***********/
- enum v4l2_buf_type types;//开始捕捉图像数据
- types = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- ret = ioctl(fd, VIDIOC_STREAMON, &types);
- if (ret < 0) {
- perror("VIDIOC_STREAMON");
- return ret;
- }
- return 0;
- }
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构
- V4L2驱动程序架构一
- Hibernate 中报错 org.hibernate.QueryException: Incorrect query syntax
- 黑马程序员--多线程
- cocos2d-x中定时器的使用
- php5.3.26在mac os x 10.8.5下的 memcached.so 扩展文件
- 《S3C2440A时钟体系小结》
- V4L2驱动程序架构
- arm-linux-gdb+gdbserver环境搭建以及远程调试
- 直接拿来用!超实用的Java数组技巧攻略
- 求解1-n之间的素数
- Android 对话框(Dialog)大全 建立你自己的对话框
- 一个异或加密方案--C语言实现
- 在Windows下利用PowerShell脚本定时删除过期文件
- HDU 4753 Two Rabbits(区间DP)
- sql上一个月和下一个月