这是我很久以前写的一个程序,如今需要使用,由于东西太多,差点就没有找到。为了以后方便使用,所以把它粘出来。
我这个程序,使用的是USB camera,采集到的图像是以YUV形式的存在的,所以在查看的时候需要使用YUV格式查看工具。
//图像采集
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h>
#include <fcntl.h>
#include <unistd.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 <time.h>
#include <asm/types.h>
#include <linux/videodev2.h>
#include <linux/fb.h>
#include <time.h>
//要访问的camera设备
#define CAMERA_DEVICE "/dev/video0"
//图片最大边界
#define MAXWIDTH 2560
#define MAXHEIGHT 1920
//默认图片的大小
#define DEFWIDTH 720
#define DEFHEIGHT 576
//采集图像的大小
#define WIDTH 640
#define HEIGHT 480
//申请缓冲区的个数
#define BUFFER_COUNT 4
//保存图片的数目
#define NUMBER 10
static int fd;
static struct v4l2_capability cap;
struct v4l2_fmtdesc fmtdesc;
struct v4l2_format fmt;
struct v4l2_streamparm setfps;
struct v4l2_requestbuffers req;
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
//用户空间
typedef struct buffer
{
void * start;
unsigned int length;
}BUFFERS;
BUFFERS *buffers;
struct v4l2_buffer buf;
enum v4l2_buf_type type;
//初始化 v4l2
int init_v4l2(void)
{
int i;
int ret = 0;
//opendev
fd = open(CAMERA_DEVICE, O_RDWR|O_NONBLOCK, 0);
if (fd < 0)
{
printf("Error opening V4L2 interface\n");
return fd;
}
else
{
printf("Open camera device %d\n ", fd);
}
//query cap
ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
if(ret < 0)
{
printf("Error: unable to query device.\n");
return ret;
}
else
{
printf("\ndriver:\t\t%s\n",cap.driver);
printf("card:\t\t%s\n",cap.card);
printf("bus_info:\t%s\n",cap.bus_info);
printf("version:\t%d\n",cap.version);
printf("capabilities:\t%x\n",cap.capabilities);
if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == V4L2_CAP_VIDEO_CAPTURE)
{
printf("Camera Device: supports capture.\n");
}
else
{
printf("The camera not support capture.\n");
}
if ((cap.capabilities & V4L2_CAP_STREAMING) == V4L2_CAP_STREAMING)
{
printf("Camera Device: supports streaming.\n");
}
else
{
printf("The camera not support streaming.\n");
}
if ((cap.capabilities & V4L2_CAP_READWRITE) == V4L2_CAP_READWRITE)
{
printf("Camera Device: supports read/writ.\n");
}
else
{
printf("The camera support not read/write.\n");
}
}
//emu all support fmt
fmtdesc.index=0;
fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
printf("\nSupport format:\n");
while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1)
{
printf("\t%d.%s\n",fmtdesc.index+1,fmtdesc.description);
fmtdesc.index++;
}
//set fmt
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.height = HEIGHT;
fmt.fmt.pix.width = WIDTH;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
if(ret < 0)
{
printf("\nUnable to set format\n");
return ret;
}
//check the fmt is set to sucessed
if(ioctl(fd, VIDIOC_G_FMT, &fmt) == -1)
{
printf("Unable to get format\n");
return ret;
}
else
{
printf("\nfmt.type:\t\t%d\n",fmt.type);
printf("pix.pixelformat:\t%c%c%c%c\n",fmt.fmt.pix.pixelformat & 0xFF,
(fmt.fmt.pix.pixelformat >> 8) & 0xFF,
(fmt.fmt.pix.pixelformat >> 16) & 0xFF,
(fmt.fmt.pix.pixelformat >> 24) & 0xFF);
printf("pix.height:\t\t%d\n",fmt.fmt.pix.height);
printf("pix.width:\t\t%d\n",fmt.fmt.pix.width);
printf("pix.field:\t\t%d\n",fmt.fmt.pix.field);
}
//set fps (stream)
setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
setfps.parm.capture.timeperframe.numerator = 10;
setfps.parm.capture.timeperframe.denominator = 10;
ret = ioctl(fd,VIDIOC_S_PARM,&setfps);
if(ret < 0)
{
printf("set streamparm error\n");
exit(EXIT_FAILURE);
}
//检查驱动的修剪能力
ret = ioctl(fd, VIDIOC_CROPCAP, &cropcap);
if(ret < 0)
{
printf("set VIDIOC_CROPCAP failed. errno = %s\n", strerror(errno));
}
else
{
printf("The camera: max_width = %d\n\t\tmax_height = %d\n",
cropcap.bounds.width, cropcap.bounds.height);
//设置缩放
memset(&crop, 0, sizeof(crop));
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
crop.c.width = WIDTH;
crop.c.height = HEIGHT;
ret = ioctl(fd, VIDIOC_S_CROP, &crop);
if(ret < 0)
{
printf("set VIDIOC_S_CROP failed. errno = %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
printf("VIDIOC_S_CROP sucessful.\n");
}
printf("\ninit %s \t[OK]\n\n",CAMERA_DEVICE);
return 1;
}
//mmap
int mmap_v4l2()
{
int ret;
unsigned int n_buffers;
//request for 4 buffers
req.count=BUFFER_COUNT;
req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory=V4L2_MEMORY_MMAP;
ret = ioctl(fd,VIDIOC_REQBUFS,&req);
if(ret < 0)
{
printf("request for buffers error\n");
exit(EXIT_FAILURE);
}
//mmap for buffers
buffers = (BUFFERS*)calloc(req.count, sizeof (BUFFERS));
if (!buffers)
{
printf ("Out of memory\n");
exit(EXIT_FAILURE);
}
for (n_buffers = 0; n_buffers < req.count; n_buffers++)
{
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
//query buffers 读取缓存
ret = ioctl (fd, VIDIOC_QUERYBUF, &buf);
if(ret < 0)
{
printf("query buffer error\n");
exit(EXIT_FAILURE);
}
buffers[n_buffers].length = buf.length;
//map
buffers[n_buffers].start = mmap(NULL,buf.length,
PROT_READ |PROT_WRITE, MAP_SHARED,
fd, buf.m.offset);
if (buffers[n_buffers].start == MAP_FAILED)
{
printf("buffer map error\n");
exit(EXIT_FAILURE);
}
//Queen buffer
if(-1 == ioctl(fd, VIDIOC_QBUF, &buf))
{
printf("%d queue fail\n", n_buffers + 1);
exit(EXIT_FAILURE);
}
}
printf("mmap_v4l2\t\t[OK]\n\n");
return 1;
}
//Need to file number
time_t rawtime[NUMBER];
//把获得的图片 写进文件
int process_file(int m, int n)
{
int ret;
char file_name[128];
time(&rawtime[n]);
sprintf(file_name, "%ld%d", rawtime[n], n);
ret = creat(file_name, 0777);
if( ret < 0 )
{
printf("create %d file failed\n", n+1);
exit(EXIT_FAILURE);
}
FILE *fp;
fp = fopen(file_name, "rb+");
if( !fp )
{
printf("open %d error\n", n);
exit(EXIT_FAILURE);
}
//fwrite(frame_buffer, sizeof(frame_buffer), 1,fp);
fwrite(buffers[m].start, buffers[m].length, 1,fp);
fclose(fp);
return 1;
}
//图像采集 image acquisition
int image_acq()
{
int ret;
//开始视频采集
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl (fd, VIDIOC_STREAMON, &type);
if(ret < 0)
{
printf("Fail to VIDIOC_STERAMON\n");
exit(EXIT_FAILURE);
}
int nu, times = 0;
/*select的最后一个参数,表示该调用在返回前等待多久
struct timeval time;
//Timeout
time.tv_sec = TimeOut;
time.tv_usec = 0;
*/
while(1)
{
//select
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
nu = select(fd + 1, &fds, NULL, NULL, NULL);
if(nu < 0)
{
if(EINTR == errno)
continue;
printf("Fail to select, errno = %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
//把数据拿出来
ret = ioctl(fd, VIDIOC_DQBUF, &buf);
if(ret < 0)
{
printf("Fail to VIDIOC_DQBUF, errno = %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
// printf("buffer index=%d, times=%d\n", buf.index, times % 4);
//Data processing
process_file(buf.index, times);
//Queen buffer again
ret = ioctl(fd, VIDIOC_QBUF, &buf);
if(ret < 0)
{
printf("Fail to VIDIOC_QBUF, errno = %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
// printf("bytesuesd = %d\n", buf.bytesused);/* 判断采集的图>像以什么方式存储 */
printf(" %d VIDIOC_QBUF again\t [OK]\n", times + 1);
times ++ ;
if(times >= 10)
break;
//sleep(1);
}
printf("image_acq \t\t[OK]\n\n");
return 1;
}
//停止采集 及 关闭设备
void close_v4l2( void )
{
//stop_capturing
int ret;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret == ioctl(fd,VIDIOC_STREAMOFF,&type);
if(ret < 0)
{
perror("Fail to ioctl 'VIDIOC_STREAMOFF'");
exit(EXIT_FAILURE);
}
//release mmap
unsigned int i;
for(i = 0; i < BUFFER_COUNT; i++)
{
if(-1 == munmap(buffers[i].start, buffers[i].length))
{
exit(EXIT_FAILURE);
}
}
free(buffers);
//close camera device
if(-1 == close(fd))
{
printf("Fail to close fd\n");
exit(EXIT_FAILURE);
}
printf("close_v4l2\t\t[OK]\n");
}
int main()
{
if(1 != init_v4l2())
{
return -1;
}
mmap_v4l2();
image_acq();
close_v4l2();
printf("\n");
return 0;
}