#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <assert.h>
#include <linux/videodev2.h>
 
 
typedef struct
{
void *start;
int length;
}BUFTYPE;
 
BUFTYPE *user_buf;
int n_buffer = 0;
 
//打开摄像头设备
int open_camer_device()
{
int fd;
 
if((fd = open("/dev/video0",O_RDWR | O_NONBLOCK)) < 0)
{
perror("Fail to open");
exit(EXIT_FAILURE);
 
return fd;
}
 
int init_mmap(int fd)
{
int i = 0;
struct v4l2_requestbuffers reqbuf;
 
bzero(&reqbuf,sizeof(reqbuf));
reqbuf.count = 4;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP;
 
//申请视频缓冲区(这个缓冲区位于内核空间,需要通过mmap映射)
//这一步操作可能会修改reqbuf.count的值,修改为实际成功申请缓冲区个数
if(-1 == ioctl(fd,VIDIOC_REQBUFS,&reqbuf))
{
perror("Fail to ioctl 'VIDIOC_REQBUFS'");
exit(EXIT_FAILURE);
}
 
n_buffer = reqbuf.count;
 
printf("n_buffer = %d\n",n_buffer);
 
user_buf = calloc(reqbuf.count,sizeof(*user_buf));
if(user_buf == NULL){
fprintf(stderr,"Out of memory\n");
exit(EXIT_FAILURE);
}
 
//将内核缓冲区映射到用户进程空间
for(i = 0; i < reqbuf.count; i ++)
{
struct v4l2_buffer buf;
 
bzero(&buf,sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
//查询申请到内核缓冲区的信息
if(-1 == ioctl(fd,VIDIOC_QUERYBUF,&buf))
{
perror("Fail to ioctl : VIDIOC_QUERYBUF");
exit(EXIT_FAILURE);
}
 
user_buf[i].length = buf.length;
user_buf[i].start = 
mmap(
NULL,/*start anywhere*/
buf.length,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,buf.m.offset
);
if(MAP_FAILED == user_buf[i].start)
{
perror("Fail to mmap");
exit(EXIT_FAILURE);
}
}
 
return 0;
}
 
//初始化视频设备
int init_camer_device(int fd)
{
struct v4l2_fmtdesc fmt;
struct v4l2_capability cap;
struct v4l2_format stream_fmt;
int ret;
 
//当前视频设备支持的视频格式
memset(&fmt,0,sizeof(fmt));
fmt.index = 0;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
while((ret = ioctl(fd,VIDIOC_ENUM_FMT,&fmt)) == 0)
{
fmt.index ++ ;
 
printf("{pixelformat = %c%c%c%c},description = '%s'\n",
fmt.pixelformat & 0xff,(fmt.pixelformat >> 8)&0xff,
(fmt.pixelformat >> 16) & 0xff,(fmt.pixelformat >> 24)&0xff,
fmt.description);
}
 
//查询视频设备驱动的功能
ret = ioctl(fd,VIDIOC_QUERYCAP,&cap);
if(ret < 0){
perror("FAIL to ioctl VIDIOC_QUERYCAP");
exit(EXIT_FAILURE);
}
 
//判断是否是一个视频捕捉设备
if(!(cap.capabilities & V4L2_BUF_TYPE_VIDEO_CAPTURE))
{
printf("The Current device is not a video capture device\n");
exit(EXIT_FAILURE);
 
}
 
//判断是否支持视频流形式
if(!(cap.capabilities & V4L2_CAP_STREAMING))
{
printf("The Current device does not support streaming i/o\n");
exit(EXIT_FAILURE);
}
 
//设置摄像头采集数据格式,如设置采集数据的
//长,宽,图像格式(JPEG,YUYV,MJPEG等格式)
stream_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
stream_fmt.fmt.pix.width = 680;
stream_fmt.fmt.pix.height = 480;
stream_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
stream_fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
 
if(-1 == ioctl(fd,VIDIOC_S_FMT,&stream_fmt))
{
perror("Fail to ioctl");
exit(EXIT_FAILURE);
}
 
//初始化视频采集方式(mmap)
init_mmap(fd);
 
return 0;
}
 
int start_capturing(int fd)
{
unsigned int i;
enum v4l2_buf_type type;
 
//将申请的内核缓冲区放入一个队列中
for(i = 0;i < n_buffer;i ++)
{
struct v4l2_buffer buf;
 
bzero(&buf,sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
 
if(-1 == ioctl(fd,VIDIOC_QBUF,&buf))
{
perror("Fail to ioctl 'VIDIOC_QBUF'");
exit(EXIT_FAILURE);
}
}
 
//开始采集数据
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(-1 == ioctl(fd,VIDIOC_STREAMON,&type))
{
printf("i = %d.\n",i);
perror("Fail to ioctl 'VIDIOC_STREAMON'");
exit(EXIT_FAILURE);
}
 
return 0;
}
 
//将采集好的数据放到文件中
int process_image(void *addr,int length)
{
FILE *fp;
static int num = 0;
char picture_name[20];
 
sprintf(picture_name,"picture%d.jpg",num ++);
 
if((fp = fopen(picture_name,"w")) == NULL)
{
perror("Fail to fopen");
exit(EXIT_FAILURE);
}
 
fwrite(addr,length,1,fp);
usleep(500);
 
fclose(fp);
 
return 0;
}
 
int read_frame(int fd)
{
struct v4l2_buffer buf;
unsigned int i;
 
bzero(&buf,sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
 
//从队列中取缓冲区
if(-1 == ioctl(fd,VIDIOC_DQBUF,&buf))
{
perror("Fail to ioctl 'VIDIOC_DQBUF'");
exit(EXIT_FAILURE);
}
 
assert(buf.index < n_buffer);
//读取进程空间的数据到一个文件中
process_image(user_buf[buf.index].start,user_buf[buf.index].length);
 
if(-1 == ioctl(fd,VIDIOC_QBUF,&buf))
{
perror("Fail to ioctl 'VIDIOC_QBUF'");
exit(EXIT_FAILURE);
}
 
return 1;
}
 
int mainloop(int fd)
int count = 10;
 
while(count -- > 0)
{
for(;;)
{
fd_set fds;
struct timeval tv;
int r;
 
FD_ZERO(&fds);
FD_SET(fd,&fds);
 
/*Timeout*/
tv.tv_sec = 2;
tv.tv_usec = 0;
 
r = select(fd + 1,&fds,NULL,NULL,&tv);
 
if(-1 == r)
{
if(EINTR == errno)
continue;
 
perror("Fail to select");
exit(EXIT_FAILURE);
}
 
if(0 == r)
{
fprintf(stderr,"select Timeout\n");
exit(EXIT_FAILURE);
}
 
if(read_frame(fd))
break;
}
}
 
return 0;
}
 
void stop_capturing(int fd)
{
enum v4l2_buf_type type;
 
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(-1 == ioctl(fd,VIDIOC_STREAMOFF,&type))
{
perror("Fail to ioctl 'VIDIOC_STREAMOFF'");
exit(EXIT_FAILURE);
}
 
return;
}
 
void uninit_camer_device()
{
unsigned int i;
 
for(i = 0;i < n_buffer;i ++)
{
if(-1 == munmap(user_buf[i].start,user_buf[i].length))
{
exit(EXIT_FAILURE);
}
}
 
free(user_buf);
 
return;
}
 
void close_camer_device(int fd)
{
if(-1 == close(fd))
{
perror("Fail to close fd");
exit(EXIT_FAILURE);
}
 
return;
}
 
int main()
{
int fd;       
                         
fd = open_camer_device();
 
init_camer_device(fd);
 
start_capturing(fd);
 
mainloop(fd);
 
stop_capturing(fd);
 
uninit_camer_device(fd);
 
close_camer_device(fd);
 
return 0;
}

注意:每个摄像头采集出来的数据格式可能不一样,一般支持MJPEG,JPEG格式的摄像头,采集出来的数据可以直接放在文件中,然后用图片查看器显示。

v4l2程序实例的更多相关文章

  1. (转)实战Memcached缓存系统(5)Memcached的CAS程序实例

    1. 非CAS 首先看一个不是CAS的Memcached程序实例.实例的问题原型,见上一篇博文. 程序实例: package com.sinosuperman.memcached; import ja ...

  2. 如何让Windows程序只运行一个程序实例?

    要实现VC++或者MFC只运行一个程序实例,一般采用互斥量来实现,即首先用互斥量封装一个只运行一个程序实例的函数接口: HANDLE hMutex = NULL; void MainDlg::RunS ...

  3. Linux Epoll介绍和程序实例

    Linux Epoll介绍和程序实例 1. Epoll是何方神圣? Epoll但是当前在Linux下开发大规模并发网络程序的热门人选,Epoll 在Linux2.6内核中正式引入,和select类似, ...

  4. 微信小程序实例源码大全

    微信小程序实例源码大全下载 微信小应用示例代码(phodal/weapp-quick)源码链接:https://github.com/phodal/weapp-quick 微信小应用地图定位demo( ...

  5. MFC 只启动一个程序实例

    问题描述: 我们开发过程中可能会经常遇到,只启动一个程序实例.即一个程序启动之后,如果再次执行该程序,将会恢复之前打开的程序,而不是打开一个新的程序. 实现原理:利用FindWindow/FindWi ...

  6. 一个完整的Installshield安装程序实例—艾泽拉斯之海洋女神出品(四) --高级设置二

    原文:一个完整的Installshield安装程序实例-艾泽拉斯之海洋女神出品(四) --高级设置二 上一篇:一个完整的安装程序实例—艾泽拉斯之海洋女神出品(三) --高级设置一4. 根据用户选择的组 ...

  7. 微信小程序实例教程(一)

    序言 开始开发应用号之前,先看看官方公布的「小程序」教程吧!(以下内容来自微信官方公布的「小程序」开发指南) 本文档将带你一步步创建完成一个微信小程序,并可以在手机上体验该小程序的实际效果.这个小程序 ...

  8. JDBC 程序实例小练习

    JDBC 程序实例问题 编程实现如下功能:在数据库中建立一个表,表名为student,其结构为学号.姓名.性别.年龄.英语.JavaSE程序设计.初级日语.总分,在表中输入多条记录. 学生的总分信息, ...

  9. C++程序实例唯一方案,窗口只打开一次,程序只打开一次

    首先是方法: // IsAlreadyRunning - 是否已经运行 BOOL IsAlreadyRunning() { BOOL bRet = FALSE; HANDLE hMutex = ::C ...

随机推荐

  1. PHP 7.1.15安装zabbix-3.2.6出现问题解决

    出现问题,显示 A non well formed numeric value encountered [zabbix.php:21 → require_once() → ZBase->run( ...

  2. 自学python到找到工作的心得

    先做个自我介绍,我13年考上一所很烂专科民办的学校,学的是生物专业,具体的学校名称我就不说出来献丑了.13年我就辍学了,我在那样的学校,一年学费要1万多,但是根本没有人学习,我实在看不到希望,我就退学 ...

  3. 基础框架整合-ssm框架+前后台交互完整教程

    1.基本概念 ssm:spring+springMVC+mybatis 2.开发环境 Eclipse mars + jdk1.7 + maven + tomcat7 3.使用maven构建web项目 ...

  4. RGB 与 (RGB转 YCbCr再转为 RGB)的图像

           RGB 与 (RGB转 YCbCr再转为 RGB)的图像   不可逆,能够从 矩阵的逆运算看出来. 附上 matlab 代码:         clc,clear; Source=imr ...

  5. tomcat内存大小设置

    tomcat内存大小设置 如果安装为windows服务,需要进行内存设置的时候,选择configure...界面, 在Java Tab页面内可以进行内存参数的设置. 学习了:http://elf884 ...

  6. 数论(同余+hash)

    Time Limit:3000MS Memory Limit:65536KB Description You are given a sequence a[0]a[1] ... a[N-1] of d ...

  7. CSDN--十年

    昨天获得了博客专家的勋章,惊喜总是来的有点意外.这个勋章也算是来的一波三折.借着这个机会,回首一下我在CSDN的博客历史. 这个博客如今可查的最早的文章,是04年下半年写的,事实上之前应该另一些自己写 ...

  8. POJ - 3257 Cow Roller Coaster (背包)

    题目大意:要用N种材料建一条长为L的路,如今给出每种材料的长度w.起始地点x.发费c和耐久度f 问:在预算为B的情况下,建好这条路的最大耐久度是多少 解题思路:背包问题 dp[i][j]表示起始地点为 ...

  9. Line(扩展欧几里得)

    题意:本题给出一个直线,推断是否有整数点在这条直线上: 分析:本题最重要的是在给出的直线是不是平行于坐标轴,即A是不是为0或B是不是为0..此外.本题另一点就是C输入之后要取其相反数,才干进行扩展欧几 ...

  10. COCOS学习笔记--Cocod2dx内存管理(三)-Coco2d-x内存执行原理

    通过上两篇博客.我们对Cocos引用计数和Ref类.PoolManager类以及AutoreleasePool类已有所了解,那么接下来就通过举栗子来进一步看看Coco2d-x内存执行原理是如何的. / ...