#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <string.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
struct v4l2_capability cap;
struct v4l2_format fmt;
struct v4l2_requestbuffers req_buf;
struct v4l2_buffer kbuf;
enum v4l2_buf_type buf_type;
int i;
struct video_buffer{
void * start;
int length;
};
struct video_buffer *buffer;
int open_camera(void)
{
int fd;
fd = open("/dev/video0",O_RDWR);
if(fd < 0){
perror("open /dev/video0 is fail");
return -1;
}
return fd;
}
int check_device(int fd)
{
if(ioctl(fd,VIDIOC_QUERYCAP,&cap) == -1){
perror("query device is fail");
return -1;
}
if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)){
return -1;
}
return 0;
}
int set_camera_fmt(int fd)
{
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
//分辨率
fmt.fmt.pix.width = 720;
fmt.fmt.pix.height = 576;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
if(ioctl(fd,VIDIOC_S_FMT,&fmt) == -1){
perror("set camera fmt is fail");
return -1;
}
return 0;
}
int init_buffer(int fd)
{
//1.分配缓冲区 这里如果数据量大 可以多开点
req_buf.count = 4;
req_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req_buf.memory = V4L2_MEMORY_MMAP;
if(ioctl(fd,VIDIOC_REQBUFS,&req_buf) == -1){
perror("set VIDIOC_REQBUFS is fail");
return -1;
}
buffer = calloc(req_buf.count,sizeof(*buffer));
for(i=0; i<req_buf.count; i++){
kbuf.index = i;
kbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
kbuf.memory = V4L2_MEMORY_MMAP;
if(ioctl(fd,VIDIOC_QUERYBUF,&kbuf) == -1){
perror("set VIDIOC_QUERYBUF is fail");
return -1;
}
buffer[i].length = kbuf.length;
buffer[i].start = mmap(NULL,kbuf.length, PROT_READ| PROT_WRITE, MAP_SHARED,fd,kbuf.m.offset);
if(ioctl(fd,VIDIOC_QBUF,&kbuf) == -1){
perror("set VIDIOC_QBUF is fail");
return -1;
}
}
return 0;
}
int start_camera(int fd)
{
buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(ioctl(fd,VIDIOC_STREAMON,&buf_type) == -1){
perror("set VIDIOC_STREAMON is fail");
return -1;
}
return 0;
}
int stop_camera(int fd)
{
buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(ioctl(fd,VIDIOC_STREAMOFF,&buf_type) == -1){
perror("set VIDIOC_STREAMON is fail");
return -1;
}
return 0;
}
int build_picture(int fd)
{
FILE * fp;
memset(&kbuf,0,sizeof(kbuf));
kbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(ioctl(fd,VIDIOC_DQBUF,&kbuf) == -1){
perror("set VIDIOC_DQBUF is fail");
return -1;
}
fp = fopen("picture.yuv","w");
fwrite(buffer[kbuf.index].start,1,buffer[kbuf.index].length,fp);
fclose(fp);
if(ioctl(fd,VIDIOC_QBUF,&kbuf) == -1){
perror("set VIDIOC_QBUF is fail");
return -1;
}
return 0;
}
int camera_read_data(int fd)
{
int ret;
fd_set rfds;
struct timeval tim;
tim.tv_sec = 2;
tim.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
ret = select(fd+1, &rfds,NULL,NULL, &tim);
if(ret == -1){
perror("select is fail");
return -1;
}else if(ret == 0){
perror("select timeout");
return -1;
}else{
build_picture(fd);
}
return 0;
}
int data_free(int fd)
{
for(i=0; i<4; i++){
munmap(buffer[i].start,buffer[i].length);
}
free(buffer);
close(fd);
}
int main(int argc, const char *argv[])
{
int fd,ret;
//1.打开驱动
fd = open_camera();
if(fd == -1){
return -1;
}
//2.查询是否是一个摄像头设备
ret = check_device(fd);
if(ret == -1){
return -1;
}
//3.设置图像采集的格式
ret = set_camera_fmt(fd);
if(ret != 0){
return -1;
}
//4.缓冲区的操作
init_buffer(fd);
//5.开始采集数据
start_camera(fd);
//6.读取数据
camera_read_data(fd);
//7.停止采集
stop_camera(fd);
//8.释放缓冲区
data_free(fd);
return 0;
}
Camera[2] ioctl访问摄像头驱动
最新推荐文章于 2024-05-08 17:44:53 发布