//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;
}

linux - camera capture的更多相关文章

  1. Linux cooked-mode capture 格式转换

    tcpdump抓包时,如果-i选项指定为一个网卡地址,那么抓取的数据包数据链路层是以太网头部:如果指定any,则以太网头部将被替换为linux cooked capture头部 # tcpdump - ...

  2. linux -- camera shot 拍照功能

    #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> ...

  3. (转)FS_S5PC100平台上Linux Camera驱动开发详解(二)

    4-3 摄像头的初始化流程及v4l2子设备驱动 这个问题弄清楚了以后下面就来看获得Camera信息以后如何做后续的处理: 在fimc_init_global调用结束之后我们获得了OV9650的信息,之 ...

  4. (转)FS_S5PC100平台上Linux Camera驱动开发详解(一) .

     平台linuxstructlinux内核videocam 说明:        理解摄像头驱动需要四个前提:        1)摄像头基本的工作原理和S5PC100集成的Camera控制器的工作原理 ...

  5. Open images from USB camera on linux using V4L2 with OpenCV

    I have always been using OpenCV's VideoCapture API to capture images from webcam or USB cameras. Ope ...

  6. linux 下camera调试笔记【转】

    转自:https://blog.csdn.net/kevinx_xu/article/details/8801931 linux camera调试 2011-10-23 10:43:37|  分类:  ...

  7. RPi 2B python opencv camera demo example

    /************************************************************************************** * RPi 2B pyt ...

  8. 【转】 linux内核移植和驱动添加(三)

    原文网址:http://blog.chinaunix.net/uid-29589379-id-4708909.html 原文地址:linux内核移植和驱动添加(三) 作者:genehang 四,LED ...

  9. 【嵌入式开发】写入开发板Linux系统-模型S3C6410

    笔者 : 万境绝尘 转载请著名出处 最终拿到板子了, 嵌入式开发正式开启. 板子型号 : 三星 S3C6410 基于ARM11, 指令集基于arm6指令集; 为毛不是 Cortext A9的板子; 烧 ...

随机推荐

  1. linux shell的执行方式

    ./ ping.sh 这个意思 ,'./'的意思是在当前目录执行, ping.sh----------------------------------------------------------- ...

  2. [转]Clean Code Principles: Be a Better Programmer

    原文:https://www.webcodegeeks.com/web-development/clean-code-principles-better-programmer/ ----------- ...

  3. 微软小冰你这么智能 .net知道吗?

  4. RS报表从按月图表追溯到按日报表

    相信很多COGNOS开发人员看到这个标题就会感觉很轻松,追溯无非是COGNOS自带的一个下钻的功能,但是这里却是固定的条件: 要求1:A报表显示按月的图表B报表显示按日的明细 2:追溯到B的时候B的开 ...

  5. Transformer中引用iqd作为数据源导入报错TR1907与TR3312

    好久没和transform接触了,初次接触就给我送了个大礼,在选择好iqd文件执行最后一步导入的时候,要求我对数据源输入用户名密码,我连续输入了三次用户名和密码,在我十分肯定用户名和密码没错的情况下, ...

  6. ASPX导入JS,JavaScript乱码怎么办

    不管你把JS改成UTF-8还是ASCII格式,弹出都是乱码. 你只要在ASPX文件顶部加上"ResponseEncoding="gb2312" ContentType=& ...

  7. Scheme 4 Javaer-3.高阶函数

    1.3  Formulating Abstractions with Higher-Order Procedures 教材有时候依照学生的基础.从0讲起:有时候给出一个大图,然后具体地逐一介绍. 本文 ...

  8. 在第一段ionic示例的基础上增加底部导航

    demo2.html <!DOCTYPE html> <html ng-app="app"> <head> <meta charset=& ...

  9. Unity Editor Toolbar 编辑器扩展

    http://www.cnblogs.com/zhaoqingqing/p/3812368.html 1.Apply to Prefab [把改动应用到Prefab] if (GUILayout.Bu ...

  10. 弹出式菜单css

    #v_box { width: 700px; height: 610px; background: #fff; position: fixed; top: 50%; left: 50%; z-inde ...