[国嵌攻略][171][V4L2图像编程接口深度学习]

V4L2摄像编程模型

1.打开摄像头设备文件

2.获取驱动信息-VIDIOC_QUERYCAP

3.设置图像格式-VIDIOC_S_FMT

4.申请帧缓冲-VIDIOC_REQBUFS

5.获取帧缓冲的地址长度信息-VIDIOC_QUERYBUF

6.使用mmap把内核空间的帧缓冲映射到用户空间

7.帧缓冲入队列-VIDIOC_QBUF

8.开始采集图像-VIDIOC_STREAMON

9.取出帧缓冲(出队)-VIDIOC_DQBUF

10.访问帧缓冲

11.帧缓冲重新入队-VIDIOC_QBUF

 

USB摄像头驱动工作流程

摄像头驱动从输入队列中取出一个帧缓冲,放到输出队列中。

应用程序从输出队列中取出一个帧缓冲,读取数据后,再把帧缓冲放入输入缓存中。

 

camera.c

#include <stdio.h>
#include <malloc.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>

struct buffer{
    void *start;   //帧缓冲地址
    int  length;   //帧缓冲长度
};

int main(int argc, char **argv){
    //创建图片文件
    int fd_img;
    
    fd_img = open("img.jpg", O_RDWR | O_CREAT, 0777);
    
    //打开设备文件
    int fd_dev;
    
    fd_dev = open("/dev/video0", O_RDWR | O_NONBLOCK, 0);
    
    //获取驱动信息
    struct v4l2_capability cap;
    
    ioctl(fd_dev, VIDIOC_QUERYCAP, &cap);
    
    printf("Driver name:%s\nCard name:%s\nBus info:%s\n\n", cap.driver, cap.card, cap.bus_info);
    
    //设置图像格式
    struct v4l2_format fmt;
    
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width = 320;
    fmt.fmt.pix.height = 240;
    fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
    
    ioctl(fd_dev, VIDIOC_S_FMT, &fmt);
    
    //申请图像缓冲
    struct v4l2_requestbuffers req;
    
    req.count = 4;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    
    ioctl(fd_dev, VIDIOC_REQBUFS, &req);
    
    //映射用户空间
    int i;
    struct buffer *buffs;
    struct v4l2_buffer buff;

    buffs = calloc(req.count, sizeof(*buffs));
    
    for(i = 0; i < req.count; i++){
        //获取缓冲长度
        buff.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buff.memory = V4L2_MEMORY_MMAP;
        buff.index = i;
        
        ioctl(fd_dev, VIDIOC_QUERYBUF, &buff);
        
        buffs[i].length = buff.length;
        
        //映射缓冲地址
        buffs[i].start = mmap(NULL, buff.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd_dev, buff.m.offset);
    }
    
    //图像缓冲入队
    for(i = 0; i < req.count; i++){
        buff.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buff.memory = V4L2_MEMORY_MMAP;
        buff.index = i;
        
        ioctl(fd_dev, VIDIOC_QBUF, &buff);
    }
    
    //捕获图像数据
    enum v4l2_buf_type type;
    
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ioctl(fd_dev, VIDIOC_STREAMON, &type);
    
    //等待捕获完成
    fd_set fds;
    
    FD_ZERO(&fds);
    FD_SET(fd_dev, &fds);
    
    select(fd_dev + 1, &fds, NULL, NULL, NULL);
    
    //图像缓冲出队
    buff.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buff.memory = V4L2_MEMORY_MMAP;
    
    ioctl(fd_dev, VIDIOC_DQBUF, &buff);
    
    //读取图像数据
    write(fd_img, buffs[buff.index].start, buffs[buff.index].length);
    
    //图像缓冲入队
    ioctl(fd_dev, VIDIOC_QBUF, &buff);
    
    //释放用户空间
    for(i = 0; i < req.count; i++){
        munmap(buffs[i].start, buffs[i].length);
    }
    
    //关闭打开文件
    close(fd_dev);
    close(fd_img);
    
    printf("Camera done!\n");
    
    return 0;
}

 

posted @ 2016-03-31 14:40  盛夏夜  阅读(360)  评论(0编辑  收藏  举报