//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. CentOS6.4下Samba服务器的安装与配置

    一.先恶狠狠地吐槽一下: 这篇随笔真是让我折腾了2天2夜才敢下笔写!!!为什么呢?之前是通过去Samba的官网下载的源码包,也就是.tar.gz来进行安装配置,不过这个让我折腾来折腾去就是没折腾出结果 ...

  2. 浏览器自动化测试初探 - 使用phantomjs与casperjs

    收录待用,修改转载已取得腾讯云授权 作者:yangchunwen 首先要解释一下为什么叫浏览器自动化测试,因为本文只关注发布后页面功能的自动化测试,也就是UI层面的自动化. 浏览器测试有别于js代码的 ...

  3. idea maven 报-source 1.5 中不支持 diamond 运算符

    需要修改 project setting 中的

  4. 【转】javascript 中的很多有用的东西

    原文:https://www.cnblogs.com/ys-ys/p/5158510.html ---------------------------------------------------- ...

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

  6. Opencv 完美配置攻略 2014 (Win8.1 + Opencv 2.4.8 + VS 2013)

    http://my.phirobot.com/blog/2014-02-opencv_configuration_in_vs.html 2012年4月给同学写了篇傻瓜式的 VS2010+Opencv- ...

  7. ScriptableObject 对象化的运用

    http://www.cnblogs.com/oldman/articles/2409554.html using UnityEngine; using UnityEditor; using Syst ...

  8. Patterns-Proxy

    http://blog.csdn.net/jianghuxiaoxiami/article/details/3403924 1.代理模式 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问 ...

  9. 〖Android〗CM10.2编译错误解决

    错误1: hardware/samsung/exynos4/hal/libhdmi/SecHdmi/SecHdmiV4L2Utils.cpp: In function 'int android::hd ...

  10. 【TP3.2与TP5.0区别】

    Tp3.2 和 Tp5.0之间的区别   5.0版本和之前版本的差异较大,本篇对熟悉3.2版本的用户给出了一些5.0的主要区别. URL和路由 5.0的URL访问不再支持普通URL模式,路由也不支持正 ...