您的位置:首页 > 其它

图像采集--V4L2

2014-03-05 16:36 211 查看
这是我很久以前写的一个程序,如今需要使用,由于东西太多,差点就没有找到。为了以后方便使用,所以把它粘出来。

我这个程序,使用的是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
);
sprintf(file_name, "%ld%d", rawtime
, 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: