/*
* 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); //成功,返回一个非负整数;出错,返回EOF。fputs(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_DQBUF和VIDIOC_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小时内删除。
发表评论