V4L2编程使用USB摄像头生成一张图片

//cut a picture
#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>
 
#define CLEAR(x) memset (&(x), 0, sizeof (x))
 
struct buffer {
        void *                  start;
        size_t                  length;
};
 
static char *           dev_name        = "/dev/video2";//摄像头设备名
static int              fd              = -1;
struct buffer *         buffers         = NULL;
static unsigned int     n_buffers       = 0;

#define VIDEO_WIDTH 640
#define VIDEO_HEIGHT 480
#define VIDEO_FORMAT V4L2_PIX_FMT_MJPEG
                   //V4L2_PIX_FMT_JPEG
                   //V4L2_PIX_FMT_YUYV
                   //V4L2_PIX_FMT_YVU420
                   //V4L2_PIX_FMT_RGB32


FILE *file_fd;
#define CAPTURE_FILE "test.jpg"
static unsigned long file_length;

//
//获取一帧数据
//从视频缓冲区的输出队列中取得一个已经保存有一帧视频数据的视频缓冲区
//
static int read_frame (void)
{
     struct v4l2_buffer buf;
     CLEAR (buf);
     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     buf.memory = V4L2_MEMORY_MMAP;
     if(ioctl (fd, VIDIOC_DQBUF, &buf) == -1)
       {
          printf("VIDIOC_DQBUF failture\n"); //出列采集的帧缓冲
          exit(1);
       }

     assert (buf.index < n_buffers);
   //  printf ("buf.index dq is %d,\n",buf.index);
 
  //将其写入文件中
     fwrite(buffers[buf.index].start, buffers[buf.index].length, 1, file_fd);
      printf("Capture one frame saved in %s\n", CAPTURE_FILE);
     //再将其入列
     if(ioctl (fd, VIDIOC_QBUF, &buf)<0)
     printf("failture VIDIOC_QBUF\n");
     return 1;
}
 
int main (int argc,char ** argv)
{
     file_fd = fopen(CAPTURE_FILE, "w");//图片文件名

     //打开设备
     fd = open (dev_name, O_RDWR | O_NONBLOCK, 0);
     if(fd < 0)
       {
          printf("open %s failed\n",dev_name);
          exit(1);
       }

      //获取驱动信息//获取摄像头参数//查询驱动功能并打印
      struct v4l2_capability cap;
  
      if(ioctl (fd, VIDIOC_QUERYCAP, &cap) < 0)
        {
          printf("get vidieo capability error,error code: %d \n", errno);
          exit(1);
        }
       // Print capability infomations
          printf("\nCapability Informations:\n");
          printf("Driver Name:%s\nCard Name:%s\nBus info:%s\nDriver Version:%u.%u.%u\nCapabilities: X\n",
                      cap.driver,cap.card,cap.bus_info,
                      (cap.version>>16)&0XFF, (cap.version>>8)&0XFF,cap.version&0XFF,
                      cap.capabilities );
       //获取设备支持的视频格式
       struct v4l2_fmtdesc fmtdesc;     
       CLEAR (fmtdesc);
       fmtdesc.index = 0;
       fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    printf("\nSupport format:\n");
       while ((ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) == 0)
             {
                  printf("/t%d.\n{\npixelformat = '%c%c%c%c',\ndescription = '%s'\n }\n",
                  fmtdesc.index+1,
                            fmtdesc.pixelformat & 0xFF,
                            (fmtdesc.pixelformat >> 8) & 0xFF,
                            (fmtdesc.pixelformat >> 16) & 0xFF,
                            (fmtdesc.pixelformat >> 24) & 0xFF,
                            fmtdesc.description);  
         fmtdesc.index++;
              }  
    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
     {
                   fprintf (stderr, "%s is no video capture device\n", dev_name);
                   exit (EXIT_FAILURE);
              }
///取景窗口缩放/有的摄像头不支持/
 

                
   //检查是否支持某种帧格式   
   struct v4l2_format fmt2;
   fmt2.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;   
   fmt2.fmt.pix.pixelformat = VIDEO_FORMAT;

   if(ioctl(fd,VIDIOC_TRY_FMT,&fmt2)==-1)  
           if(errno==EINVAL)
           printf("not support format %s!\n",VIDEO_FORMAT);   

     //设置视频捕获格式
     struct v4l2_format fmt;
     CLEAR (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 = VIDEO_FORMAT;


    //设置图像格式
     if(ioctl (fd, VIDIOC_S_FMT, &fmt) < 0)
       {
          printf("failture VIDIOC_S_FMT\n");
          exit(1);
       }
  ///
       

       
  
///
    // 显示当前帧的相关信息
     struct v4l2_format fmt3;
     fmt3.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
     ioctl(fd,VIDIOC_G_FMT,&fmt3); 
     printf("\nCurrent data format information:\n twidth:%d\n theight:%d\n",
                                     fmt3.fmt.pix.width,fmt3.fmt.pix.height);

       struct v4l2_fmtdesc fmtdes;
       fmtdes.index=0;
       fmtdes.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
       while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdes)!=-1)
       {
         if(fmtdes.pixelformat & fmt3.fmt.pix.pixelformat)
          {
            printf(" tformat:%s\n",fmtdes.description);
            break;
          }
          fmtdes.index++;
       }
///
     //视频分配捕获内存
     struct v4l2_requestbuffers req;
     CLEAR (req);
     req.count               = 4;
     req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     req.memory              = V4L2_MEMORY_MMAP;
 
     //申请缓冲,count是申请的数量
     if(ioctl (fd, VIDIOC_REQBUFS, &req) < 0)
       {
         printf("failture VIDIOC_REQBUFS\n");
         exit(1);
        }
     if (req.count < 2)
        printf("Insufficient buffer memory\n");

      //内存中建立对应空间
      //获取缓冲帧的地址、长度
       buffers = calloc (req.count, sizeof (*buffers));//在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针
     if (!buffers)
       {
          fprintf (stderr, "Out of memory/n");
          exit (EXIT_FAILURE);
        }
  
     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;// 要获取内核视频缓冲区的信息编号
 
           if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buf)) //映射用户空间
              {
                printf ("VIDIOC_QUERYBUF error\n");
                exit(-1);
              }
               buffers[n_buffers].length = buf.length; 

     // 把内核空间缓冲区映射到用户空间缓冲区
       buffers[n_buffers].start = mmap (NULL ,    //通过mmap建立映射关系
                                        buf.length,
                                        PROT_READ | PROT_WRITE ,
                                        MAP_SHARED ,
                                        fd,
                                        buf.m.offset);
 
          if (MAP_FAILED == buffers[n_buffers].start)
             {
               printf ("mmap failed\n");
            exit(1);
             }
        }

//投放一个空的视频缓冲区到视频缓冲区输入队列中
//把四个缓冲帧放入队列,并启动数据流
        unsigned int i;
    // 将缓冲帧放入队列
       enum v4l2_buf_type type;
       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; //指定要投放到视频输入队列中的内核空间视频缓冲区的编号;
 
               if (-1 == ioctl (fd, VIDIOC_QBUF, &buf))//申请到的缓冲进入列队
               printf ("VIDIOC_QBUF failed\n");
            }
    //开始捕捉图像数据  
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (-1 == ioctl (fd, VIDIOC_STREAMON, &type))
       {
          printf ("VIDIOC_STREAMON failed\n");
          exit(1);
       }

/
 for (;;) //这一段涉及到异步IO
 {
   fd_set fds;
   struct timeval tv;
   int r;
 
   FD_ZERO (&fds);//将指定的文件描述符集清空
   FD_SET (fd, &fds);//在文件描述符集合中增加一个新的文件描述符
 
  
   tv.tv_sec = 2;
   tv.tv_usec = 0;
 
   r = select (fd + 1, &fds, NULL, NULL, &tv);//判断是否可读(即摄像头是否准备好),tv是定时

   if (-1 == r)
    {
      if (EINTR == errno)
      continue;
      printf ("select err\n");
    }
   if (0 == r)
    {
      fprintf (stderr, "select timeout\n");
      exit (EXIT_FAILURE);
    }
   if (read_frame ())//如果可读,执行read_frame ()函数,并跳出循环
   break;
 }
 /// Release the resource  
   unsigned int ii;
    for (ii = 0; ii < n_buffers; ++ii)
   if (-1 == munmap (buffers[ii].start, buffers[ii].length))   
       free (buffers);
 
 /

close (fd);
printf("Camera test Done.\n");
fclose (file_fd);
//exit (EXIT_SUCCESS);
return 0;
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值