移动物体监控系统-sprint2摄像头子系统开发

一、摄像头使能驱动

1.1 摄像头软件系统构架

  

摄像头采集系统按照上图,硬件(摄像头)->摄像头驱动 ->V4L2接口规范 ->图像采集(应用)。V4L2将不同类型的摄像头设备按照统一的接口规范进行图像采集!!!

1.2 摄像头驱动的使能配置

  (1)在linux-smart210目录下执行 "make menuconfig ARCH+arm"

  (2)依次选择如下配置选项  

    Device Drivers --->

      Multimedia support --->

        [*]video for linux --->

        [*]video capture adapters --->

          [*]V2L usb devices ---> (支持V4L2接口

            <*>GSPCA based webcams --->(万能摄像头驱动

              <*>ZC3XX usb camers Drivers (具体usb摄像头对应的驱动程序

  (3)编译新内核(make uImage ARCH=arm CROSS _COMPILE=arm=linux),内核下载至开发板,摄像头开发环境搭建完成。

  (4)摄像头测试程序 camers.c

    编译" arm-linux-gcc camera.c -o camera ",将生成的应用程序拷贝到开发板,插入USB摄像头至开发板显示驱动连接信息,执行./camera,即可捕获采集的图像。

二、V4L2编程接口基础设计

  part1:V4L2设计构架图

  

  由上图,内核空间中帧缓冲中存储中着摄像头驱动采集的图像信息,用户空间的应用程序需要获取采集到的图像,则需要对帧缓冲进行一下处理:

    取出帧缓冲(出队列) ->读取帧缓冲中的数据 -> 放回帧缓冲(入队)

  part2:V4L2摄像头编程模型

  1、打开摄像头设备文件 ("/dev/video0");

  2、获取驱动信息 (ioctl_fd,VIDIOC_QIERYCAP,&cap) 

  3、设置图像格式 (VIDIOC_S_FMT) 

  4、申请帧缓冲 (VIDIOC_REQBUFS)

    5、获取帧缓冲长度信息 (VIDIOC_QUERYBUF)

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

    7、帧缓冲入队列 (VIDIOC_QBUF)

  8、开始采集图像 (VIDIOC_STREAMON)

    9、取出帧缓冲(出队)(VIDIOC_DQBUF)

    10、访问帧缓冲 (write/read)

    11、帧缓冲重新入队 (VIDIOC_QBUF)

  part3:V4L2编程

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h>           
#include <fcntl.h>            
#include <unistd.h>
#include <errno.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
 
#include <asm/types.h>        
#include <linux/videodev2.h>
  
struct buffer {
        void *                  start;
        size_t                  length;
};
 
struct buffer *buffers;
unsigned long  n_buffers;
unsigned long file_length;

int file_fd;
char *dev_name = "/dev/video3";
int fd;

static int read_frame (void)
{
     struct v4l2_buffer buf;
     
     /*帧出列*/
     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;   //V4L2_BUF_TYPE_VIDEO_CAPTURE:1
     buf.memory = V4L2_MEMORY_MMAP;
     ioctl (fd, VIDIOC_DQBUF, &buf);

     write(file_fd,buffers[buf.index].start,buffers[buf.index].length);
     
     /*buf入列*/
     ioctl(fd, VIDIOC_QBUF, &buf);

     return 1;
}
 
int main (int argc,char ** argv)
{
     struct v4l2_capability cap;
     struct v4l2_format fmt;
     struct v4l2_requestbuffers req;
     struct v4l2_buffer buf; 
     unsigned int i;
     enum v4l2_buf_type type;
     
      
     file_fd = open("test.jpg", O_RDWR | O_CREAT, 0777);
    //1.打开摄像头设备文件
     fd = open (dev_name, O_RDWR | O_NONBLOCK, 0); 

     /*2.获取驱动信息*/
      ioctl (fd, VIDIOC_QUERYCAP, &cap);
      printf("Driver Name:%s\n Card Name:%s\n Bus info:%s\n\n",cap.driver,cap.card,cap.bus_info);
          
     /*3.设置图像格式*/
     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, VIDIOC_S_FMT, &fmt) ;
      
     /*4.申请图像缓冲区*/
     req.count               = 4;
     req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     req.memory              = V4L2_MEMORY_MMAP;
     ioctl (fd, VIDIOC_REQBUFS, &req);   
     
     buffers = calloc (req.count, sizeof (*buffers));    
  
     for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
     { 
           /*4.1获取图像缓冲区的信息*/
           buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
           buf.memory      = V4L2_MEMORY_MMAP;
           buf.index       = n_buffers;
 
           ioctl (fd, VIDIOC_QUERYBUF, &buf); 
             
           buffers[n_buffers].length = buf.length; 
           
           // 4.2把内核空间中的图像缓冲区映射到用户空间
          buffers[n_buffers].start = mmap (NULL ,    //通过mmap建立映射关系
                                        buf.length,
                                        PROT_READ | PROT_WRITE ,
                                        MAP_SHARED ,
                                        fd,
                                        buf.m.offset);
     }

        
     /*4.3图像缓冲入队*/ 
       
       for (i = 0; i < n_buffers; ++i)
       {
               buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
               buf.memory      = V4L2_MEMORY_MMAP;
               buf.index       = i; 
               ioctl (fd, VIDIOC_QBUF, &buf);
               
       }
    
    //4.4开始捕捉图像数据  
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ioctl (fd, VIDIOC_STREAMON, &type);

   fd_set fds;

   FD_ZERO (&fds);
   FD_SET (fd, &fds);

   select(fd + 1, &fds, NULL, NULL, NULL);
   
   /*4.5读取一幅图像*/
   read_frame();

   for (i = 0; i < n_buffers; ++i)
      munmap (buffers[i].start, buffers[i].length);    

   close (fd);
   close (file_fd);
   printf("Camera Done.\n");

   return 0;
}

 

posted @ 2020-08-03 14:14  打打打个大西瓜  阅读(185)  评论(0)    收藏  举报