/* 
*  V4L2 video capture example 
*  This program can be used and distributed without restrictions. 
*/ 
#include <stdio.h>
#include <stdlib.h>   
#include <string.h>   
#include <assert.h>   
#include <getopt.h>            /* getopt_long() */   
#include <fcntl.h>              /* low-level i/o */   
#include <unistd.h> /*getpid()*/
#include <error.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>          /* for videodev2.h */   
#include <linux/videodev2.h>   
#define CLEAR(x) memset(&(x), 0, sizeof (x))   
typedef enum { 
    IO_METHOD_READ, 
    IO_METHOD_MMAP, 
    IO_METHOD_USERPTR, 
} io_method; 
struct buffer { 
    void *start; 
    size_t length; 
}; 
static char *          dev_name        = NULL; 
static io_method        io              = IO_METHOD_MMAP; 
static int              fd              = -1; 
struct buffer *        buffers        = NULL; 
static unsigned int    n_buffers      = 0; 
static void errno_exit(const char *s) 
    fprintf(stderr, "%s error %d, %s\n", 
        s, errno, strerror(errno)); 
    exit(EXIT_FAILURE); 
static int xioctl(int fd,int request,void *arg) 
    int r; 
    do r = ioctl(fd, request, arg); 
    while (-1 == r && EINTR == errno); 
    return r; 
static void process_image(const void *p) 
    FILE* fp; 
    fp = fopen("test","w+"); // w+:打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
    fputs(p, fp); //成功,返回一个非负整数;出错,返回EOFfputs(const char *s,FILE *stream)作用:向指定文件写入一个字符串,缓冲区S中保存的是以‘/0’结尾的字符串,fputs将该字符串写入stream,但不写入结尾的’/0’
    fclose(fp); 
    // fflush(stdout); // fflush(stdout):清空输出缓冲区,并把缓冲区内容输出
static int read_frame(void) //用来读取一帧数据
    struct v4l2_buffer buf; 
    unsigned int i; 
    switch (io)
    { 
    case IO_METHOD_READ: 
        if (-1 == read(fd, buffers[0].start, buffers[0].length))
        { 
            switch (errno)
            { 
            case EAGAIN: //当使用不可阻断(O_NONBLOCK)打开文件后,read呼叫无可读取的数据
                return 0; 
            case EIO: //设备文件读取文件时发生输出输入错误
                /* Could ignore EIO, see spec. */ 
                /* fall through */ 
            default: 
                errno_exit("read"); 
            } 
        } 
        process_image(buffers[0].start); //保存读到的数据
        break; 
/* V4L2有一个数据缓存,存放unt数量的缓存数据。数据缓存采用FIFO的方式,当应用程序调用缓存数据时,缓存队列将最先采集到的视频数据缓存送出,并重新采集一张视频数据。这个过程需要用到两个ioctl命令,VIDIOC_DQBUFVIDIOC_QBUF*/
    case IO_METHOD_MMAP: 
        CLEAR (buf); 
        pe = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
fprintf作用
        = V4L2_MEMORY_MMAP; 
        /*出队列以取得采集数据的帧缓冲,取得原始的采集数据*/
        if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf))
        { 
            switch (errno)
            { 
            case EAGAIN: 
                return 0; 
               
            case EIO: 
                /* Could ignore EIO, see spec. */ 
                /* fall through */ 
            default: 
                errno_exit("VIDIOC_DQBUF"); 
            } 
        } 
        assert(buf.index < n_buffers); //assert的作用是计算括号内的表达式,如果其值为0,就先向stderr打印一条出错信息,然后通过abort来终止程序运行
        process_image(buffers[buf.index].start); 
        if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) //重新放入缓存队列
            errno_exit("VIDIOC_QBUF"); 
        break; 
    case IO_METHOD_USERPTR: 
        CLEAR(buf); 
        pe = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
        = V4L2_MEMORY_USERPTR; 
        if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf))
        { 
            switch (errno)
            { 
            case EAGAIN: 
                return 0; 
            case EIO: 
                /* Could ignore EIO, see spec. */ 
                /* fall through */ 
            default: 
                errno_exit("VIDIOC_DQBUF"); 
            } 
        } 
        for (i = 0; i < n_buffers; ++i) 
            if (userptr == (unsigned long) buffers[i].start 
                && buf.length == buffers[i].length) 
                break; 
            assert(i < n_buffers); 
            process_image((void *) userptr); 
            if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) 
                errno_exit("VIDIOC_QBUF"); 
            break; 
    } 
    return 1; 
/*完成图像的连续采集*/
4.  static void mainloop(void)
    unsigned int count; 
    count = 100; 
    while (count-- > 0)
    { 
        for (;;)
        { 
            fd_set fds; 
            struct timeval tv; 
            int r; 
           
            FD_ZERO(&fds); //初始化fd_set结构体变量
            FD_SET(fd, &fds);//fd_set结构体上注册文件描述
            /* Timeout. */
            tv.tv_sec = 2; //时间“2S
            tv.tv_usec = 0; 
            r = select (fd + 1, &fds, NULL, NULL, &tv); //判断是否可读(即摄像头是否准备好)tv是定时
            if (-1 == r) { 
                if (EINTR == errno) 
                    continue; 
                errno_exit("select"); 
            } 
            if (0 == r) {  //时间到,返回0
                fprintf(stderr, "select timeout\n"); 
                exit(EXIT_FAILURE); 
            } 
            if (read_frame()) //如果可读,执行read_frame函数,并跳出循环
                break; 
            /* EAGAIN - continue select loop. */ 

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。