v4l2抓取一帧图像的程序
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <linux/videodev2.h>
static char *dev_name = "/dev/video0";
struct buffer {
void *start;
size_t length;
};
struct buffer *buffers = NULL;
static unsigned int n_buffers = 0;
int main(int argc, char **argv)
{
int fd;
int ret;
//设备的打开
fd = open(dev_name, O_RDWR | O_NONBLOCK);
if (fd < 0) {
fprintf(stderr, "can not open /dev/video1\n");
return -1;
}
printf("open %s success\n", dev_name);
// 查询设备属性: VIDIOC_QUERYCAP
struct v4l2_capability cap;
memset(&cap, 0, sizeof(cap));
ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
if (ret < 0) {
fprintf(stderr, "ioctl querycap error\n");
return -1;
} else {
printf("Capability Informations:\n");
printf("\t%-15s = %s\n", "cap.driver", cap.driver);
printf("\t%-15s = %s\n", "cap.card", cap.card);
printf("\t%-15s = %s\n", "cap.bus_info", cap.bus_info);
printf("\t%-15s = 0x%x\n", "cap.version", cap.version);
}
/*===============select input device==================*/
//struct v4l2_input input;
// memset(&input, 0, sizeof(input));
// while (ioctl(fd, VIDIOC_ENUMINPUT, &input) >= 0) {
// printf("\ncmd VIDIOC_ENUMINPUT:\n");
// printf(" %-15s = %u\n", "input.index", input.index);
// printf(" %-15s = %s\n", "input.name", input.name);
// printf(" %-15s = %u\n", "input.type", input.type);
// printf(" %-15s = %u\n", "input.audioset", input.audioset);
// printf(" %-15s = %u\n", "input.tuner", input.tuner);
// //printf("%-15s = %lu\n", "input.std", input.std);
// printf(" input.index = %d\n", input.index);
// input.index++;
// }
//查询并显示所有支持的格式:VIDIOC_ENUM_FMT
struct v4l2_fmtdesc fmtdesc;
memset(&fmtdesc, 0, sizeof(fmtdesc));
fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
printf("Support format:\n");
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != -1) {
printf("\t%d.%s\n", fmtdesc.index + 1, fmtdesc.description) ;
fmtdesc.index++;
}
//查看或设置当前格式: VIDIOC_G_FMT, VIDIOC_S_FMT
printf("Set Format\n");
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 640;
fmt.fmt.pix.height = 480;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
if (ret < 0) {
fprintf(stderr, "ioctl VIDIOC_S_FMT error\n") ;
return -1;
}
ret = ioctl(fd, VIDIOC_G_FMT, &fmt);
if (ret < 0) {
fprintf(stderr, "get format failed\n") ;
}
printf("Stream Format Informations:\n");
printf("\t%-15s= %d\n", "type", fmt.type);
printf("\t%-15s= %d\n", "width", fmt.fmt.pix.width);
printf("\t%-15s= %d\n", "height", fmt.fmt.pix.height);
char fmtstr[8];
memset(fmtstr, 0, 8);
memcpy(fmtstr, &fmt.fmt.pix.pixelformat, 4);
printf("\t%-15s= %s\n", "pixelformat", fmtstr);
printf("\t%-15s= %d\n", "field", fmt.fmt.pix.field);
printf("\t%-15s= %d\n", "bytesperline", fmt.fmt.pix.bytesperline);
printf("\t%-15s= %d\n", "sizeimage", fmt.fmt.pix.sizeimage);
printf("\t%-15s= %d\n", "colorspace", fmt.fmt.pix.colorspace);
printf("\t%-15s= %d\n", "priv", fmt.fmt.pix.priv);
//printf(" raw_date: %s\n", fmt.fmt.raw_data);
//申请和管理缓冲区
//向设备申请缓冲区 VIDIOC_REQBUFS
struct v4l2_requestbuffers req;
memset(&req, 0, sizeof(req));
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ret = ioctl(fd, VIDIOC_REQBUFS, &req); //申请一个拥有四个缓冲帧的缓冲区
if (ret < 0) {
fprintf(stderr, "ioctl VIDIOC_REQBUFS error\n");
return -1;
}
//将四个已申请到的缓冲帧映射到应用程序,用buffers 指针记录
buffers = calloc(req.count, sizeof(*buffers)); //内存中建立对应空间
if (!buffers) {
fprintf(stderr, "Out of memory\n");
return 0;
}
struct v4l2_buffer buf;
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;
//查询序号为n_buffers 的缓冲区,得到其起始物理地址和大小
if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) {
printf("ioctl VIDIOC_QUERYBUF failed\n");
return -1;
}
printf("buf.length = %d\n", buf.length);
buffers[n_buffers].length = buf.length;
//映射内存
buffers[n_buffers].start =
mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, buf.m.offset);
if (MAP_FAILED == buffers[n_buffers].start)
printf("map buffers failed\n");
// //把四个缓冲帧放入队列
// if (ioctl(fd, VIDIOC_QBUF, &buf) < 0)
// printf("ioctl VIDIOC_QBUF failed\n");
}
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;
if (ioctl(fd, VIDIOC_QBUF, &buf) < 0)
printf("ioctl VIDIOC_QBUF failed\n");
}
//缓冲区处理好之后,就可以开始获取数据了
//启动 或 停止数据流 VIDIOC_STREAMON, VIDIOC_STREAMOFF
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(fd, VIDIOC_STREAMON, &type);
if (ret < 0)
printf("ioctl VIDIOC_STREAMON failed\n");
fd_set fds;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = 2;
tv.tv_usec = 0;
ret = select(fd + 1, &fds, NULL, NULL, &tv);
if (-1 == ret) {
if (EINTR == errno)
printf("fail to select\n");
}
if (0 == ret) {
fprintf(stderr, "select Timeout\n");
}
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
//取出一帧
ret = ioctl(fd, VIDIOC_DQBUF, &buf);
if (ret < 0)
printf("ioctl VIDIOC_DQBUF\n");
//处理一帧
FILE *file_fd;
file_fd = fopen("frame.jpg", "w");
if (file_fd < 0)
printf("create file failed\n");
fwrite(buffers[buf.index].start, 1, buffers[buf.index].length, file_fd);
printf("buffers[buf.index].length = %d\n", buffers[buf.index].length);
usleep(500);
fclose(file_fd);
if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
return -1;
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
if (ret < 0)
printf("ioctl VIDIOC_STREAMOFF failed\n");
for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
munmap(buffers[n_buffers].start, buffers[n_buffers].length);
}
free(buffers);
close(fd);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <linux/videodev2.h>
static char *dev_name = "/dev/video0";
struct buffer {
void *start;
size_t length;
};
struct buffer *buffers = NULL;
static unsigned int n_buffers = 0;
int main(int argc, char **argv)
{
int fd;
int ret;
//设备的打开
fd = open(dev_name, O_RDWR | O_NONBLOCK);
if (fd < 0) {
fprintf(stderr, "can not open /dev/video1\n");
return -1;
}
printf("open %s success\n", dev_name);
// 查询设备属性: VIDIOC_QUERYCAP
struct v4l2_capability cap;
memset(&cap, 0, sizeof(cap));
ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
if (ret < 0) {
fprintf(stderr, "ioctl querycap error\n");
return -1;
} else {
printf("Capability Informations:\n");
printf("\t%-15s = %s\n", "cap.driver", cap.driver);
printf("\t%-15s = %s\n", "cap.card", cap.card);
printf("\t%-15s = %s\n", "cap.bus_info", cap.bus_info);
printf("\t%-15s = 0x%x\n", "cap.version", cap.version);
}
/*===============select input device==================*/
//struct v4l2_input input;
// memset(&input, 0, sizeof(input));
// while (ioctl(fd, VIDIOC_ENUMINPUT, &input) >= 0) {
// printf("\ncmd VIDIOC_ENUMINPUT:\n");
// printf(" %-15s = %u\n", "input.index", input.index);
// printf(" %-15s = %s\n", "input.name", input.name);
// printf(" %-15s = %u\n", "input.type", input.type);
// printf(" %-15s = %u\n", "input.audioset", input.audioset);
// printf(" %-15s = %u\n", "input.tuner", input.tuner);
// //printf("%-15s = %lu\n", "input.std", input.std);
// printf(" input.index = %d\n", input.index);
// input.index++;
// }
//查询并显示所有支持的格式:VIDIOC_ENUM_FMT
struct v4l2_fmtdesc fmtdesc;
memset(&fmtdesc, 0, sizeof(fmtdesc));
fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
printf("Support format:\n");
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != -1) {
printf("\t%d.%s\n", fmtdesc.index + 1, fmtdesc.description) ;
fmtdesc.index++;
}
//查看或设置当前格式: VIDIOC_G_FMT, VIDIOC_S_FMT
printf("Set Format\n");
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 640;
fmt.fmt.pix.height = 480;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
if (ret < 0) {
fprintf(stderr, "ioctl VIDIOC_S_FMT error\n") ;
return -1;
}
ret = ioctl(fd, VIDIOC_G_FMT, &fmt);
if (ret < 0) {
fprintf(stderr, "get format failed\n") ;
}
printf("Stream Format Informations:\n");
printf("\t%-15s= %d\n", "type", fmt.type);
printf("\t%-15s= %d\n", "width", fmt.fmt.pix.width);
printf("\t%-15s= %d\n", "height", fmt.fmt.pix.height);
char fmtstr[8];
memset(fmtstr, 0, 8);
memcpy(fmtstr, &fmt.fmt.pix.pixelformat, 4);
printf("\t%-15s= %s\n", "pixelformat", fmtstr);
printf("\t%-15s= %d\n", "field", fmt.fmt.pix.field);
printf("\t%-15s= %d\n", "bytesperline", fmt.fmt.pix.bytesperline);
printf("\t%-15s= %d\n", "sizeimage", fmt.fmt.pix.sizeimage);
printf("\t%-15s= %d\n", "colorspace", fmt.fmt.pix.colorspace);
printf("\t%-15s= %d\n", "priv", fmt.fmt.pix.priv);
//printf(" raw_date: %s\n", fmt.fmt.raw_data);
//申请和管理缓冲区
//向设备申请缓冲区 VIDIOC_REQBUFS
struct v4l2_requestbuffers req;
memset(&req, 0, sizeof(req));
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ret = ioctl(fd, VIDIOC_REQBUFS, &req); //申请一个拥有四个缓冲帧的缓冲区
if (ret < 0) {
fprintf(stderr, "ioctl VIDIOC_REQBUFS error\n");
return -1;
}
//将四个已申请到的缓冲帧映射到应用程序,用buffers 指针记录
buffers = calloc(req.count, sizeof(*buffers)); //内存中建立对应空间
if (!buffers) {
fprintf(stderr, "Out of memory\n");
return 0;
}
struct v4l2_buffer buf;
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;
//查询序号为n_buffers 的缓冲区,得到其起始物理地址和大小
if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) {
printf("ioctl VIDIOC_QUERYBUF failed\n");
return -1;
}
printf("buf.length = %d\n", buf.length);
buffers[n_buffers].length = buf.length;
//映射内存
buffers[n_buffers].start =
mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, buf.m.offset);
if (MAP_FAILED == buffers[n_buffers].start)
printf("map buffers failed\n");
// //把四个缓冲帧放入队列
// if (ioctl(fd, VIDIOC_QBUF, &buf) < 0)
// printf("ioctl VIDIOC_QBUF failed\n");
}
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;
if (ioctl(fd, VIDIOC_QBUF, &buf) < 0)
printf("ioctl VIDIOC_QBUF failed\n");
}
//缓冲区处理好之后,就可以开始获取数据了
//启动 或 停止数据流 VIDIOC_STREAMON, VIDIOC_STREAMOFF
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(fd, VIDIOC_STREAMON, &type);
if (ret < 0)
printf("ioctl VIDIOC_STREAMON failed\n");
fd_set fds;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = 2;
tv.tv_usec = 0;
ret = select(fd + 1, &fds, NULL, NULL, &tv);
if (-1 == ret) {
if (EINTR == errno)
printf("fail to select\n");
}
if (0 == ret) {
fprintf(stderr, "select Timeout\n");
}
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
//取出一帧
ret = ioctl(fd, VIDIOC_DQBUF, &buf);
if (ret < 0)
printf("ioctl VIDIOC_DQBUF\n");
//处理一帧
FILE *file_fd;
file_fd = fopen("frame.jpg", "w");
if (file_fd < 0)
printf("create file failed\n");
fwrite(buffers[buf.index].start, 1, buffers[buf.index].length, file_fd);
printf("buffers[buf.index].length = %d\n", buffers[buf.index].length);
usleep(500);
fclose(file_fd);
if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
return -1;
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
if (ret < 0)
printf("ioctl VIDIOC_STREAMOFF failed\n");
for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
munmap(buffers[n_buffers].start, buffers[n_buffers].length);
}
free(buffers);
close(fd);
return 0;
}