/******************v4l2.c******************/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/videodev.h>
#ifdef ANDROID_ENV
#define LOG LOGV
#else
#define LOG //
#endif
#define CAMERA_DEVICE "/dev/video0"
#define VIDEO_WIDTH 640
#define VIDEO_HEIGHT 480
#define VIDEO_FORMAT V4L2_PIX_FMT_YUYV
#define BUFFER_COUNT 1
struct fimc_buffer {
int length;
void *start;
} framebuf[BUFFER_COUNT];
int main()
{
int i, ret;
int j,k,n,m;
char name[10]={0};
int flag=1;
int fd;
fd = open(CAMERA_DEVICE, O_RDWR, 0);//设备以非阻塞方式打开
if (fd < 0)
{
LOG("Open %s failed/n", CAMERA_DEVICE);
return -1;
}
struct v4l2_capability cap;
ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);//摄像头主要功能获取
if (ret < 0)
{
LOG("VIDIOC_QUERYCAP failed (%d)/n", ret);
return ret;
}
struct v4l2_format fmt; //设置视频制式和帧格式
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = VIDEO_WIDTH;
fmt.fmt.pix.height = VIDEO_HEIGHT;
fmt.fmt.pix.pixelformat = VIDEO_FORMAT;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
if (ret < 0)
{
LOG("VIDIOC_S_FMT failed (%d)/n", ret);
return ret;
}
ret = ioctl(fd, VIDIOC_G_FMT, &fmt);//获取视频制式和帧格式的实际值,看是否设置正确
if (ret < 0)
{
LOG("VIDIOC_G_FMT failed (%d)/n", ret);
return ret;
}
struct v4l2_requestbuffers reqbuf;//向驱动申请帧缓冲
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP;
reqbuf.count = BUFFER_COUNT;
ret = ioctl(fd , VIDIOC_REQBUFS, &reqbuf);
if(ret < 0)
{
LOG("VIDIOC_REQBUFS failed (%d)/n", ret);
return ret;
}
struct v4l2_buffer buf;//获取帧缓冲地址
for(i=0; i<BUFFER_COUNT; i++)
{
buf.index = i;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(fd , VIDIOC_QUERYBUF, &buf);
if(ret < 0)
{
LOG("VIDIOC_QUERYBUF (%d) failed (%d)/n", i, ret);
return ret;
}
framebuf[i].length = buf.length;
framebuf[i].start = (char *) mmap(0, buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, buf.m.offset);//将申请到的帧缓冲映射到用户空间,就能直接操作采集的帧
if (framebuf[i].start == MAP_FAILED)
{
LOG("mmap (%d) failed: %s/n", i, strerror(errno));
return -1;
}
ret = ioctl(fd , VIDIOC_QBUF, &buf);//将申请到的帧缓冲全部入队列,以便存放数据
if (ret < 0)
{
LOG("VIDIOC_QBUF (%d) failed (%d)/n", i, ret);
return -1;
}
}
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//开始视频采集
ret = ioctl(fd, VIDIOC_STREAMON, &type);
if (ret < 0)
{
LOG("VIDIOC_STREAMON failed (%d)/n", ret);
return ret;
}
while(1)
{
for(k=0;k<10;k++)
{
ret = ioctl(fd, VIDIOC_DQBUF, &buf);//出队列以取得已采集数据的帧缓冲,取得原始数据
if (ret < 0)
{
LOG("VIDIOC_DQBUF failed (%d)/n", ret);
return ret;
}
strcpy(name,"a.jpeg");
name[0]='a'+k;
FILE *fp = fopen(name, "wb");
if (fp < 0)
{
LOG("open frame data file failed/n");
return -1;
}
fwrite(framebuf[buf.index].start, 1, buf.length, fp);
fclose(fp);
ret = ioctl(fd, VIDIOC_QBUF, &buf);//将缓冲重新入对尾,可以循环采集
if (ret < 0)
{
LOG("VIDIOC_QBUF failed (%d)/n", ret);
return ret;
}
}
}
for (i=0; i<BUFFER_COUNT; i++)
{
munmap(framebuf[i].start, framebuf[i].length);//取消映射,释放内存
}
close(fd);
LOG("Camera test Done./n");
return 0;
}
v4l2 视频采集流程程序
最新推荐文章于 2024-07-10 14:51:39 发布