#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 <asm/types.h>
#include <linux/videodev2.h>
#define CAPTURE_FILE "frame.jpg"
#define VIDEO_WIDTH 640
#define VIDEO_HEIGHT 480
#define VIDEO_FORMAT V4L2_PIX_FMT_YUYV
#define BUFFER_COUNT 4
typedef struct VideoBuffer {
void *start;
size_t length;
} VideoBuffer;
VideoBuffer framebuf[BUFFER_COUNT];
int main()
{
int i,fd;
fd = open("/dev/video0", O_RDWR);
struct v4l2_capability cap;
ioctl(fd, VIDIOC_QUERYCAP, &cap);
printf(" driver: %s\n", cap.driver);
printf(" card: %s\n", cap.card);
printf(" bus_info: %s\n", cap.bus_info);
printf(" version: %08X\n", cap.version);
printf(" capabilities: %08X\n", cap.capabilities);
// 设置视频格式
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 = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
ioctl(fd, VIDIOC_S_FMT, &fmt);
// 获取视频格式
ioctl(fd, VIDIOC_G_FMT, &fmt);
printf(" type: %d\n", fmt.type);
printf(" width: %d\n", fmt.fmt.pix.width);
printf(" height: %d\n", fmt.fmt.pix.height);
printf(" field: %d\n", fmt.fmt.pix.field);
printf(" bytesperline: %d\n", fmt.fmt.pix.bytesperline);
printf(" sizeimage: %d\n", fmt.fmt.pix.sizeimage);
printf(" colorspace: %d\n", fmt.fmt.pix.colorspace);
printf(" priv: %d\n", fmt.fmt.pix.priv);
printf(" raw_date: %s\n", fmt.fmt.raw_data);
// 请求分配内存
struct v4l2_requestbuffers reqbuf;
reqbuf.count = BUFFER_COUNT;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP;
ioctl(fd , VIDIOC_REQBUFS, &reqbuf);
struct v4l2_buffer buf;
for (i = 0; i < reqbuf.count; i++)
{
buf.index = i;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
ioctl(fd , VIDIOC_QUERYBUF, &buf);
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)
{
printf("mmap (%d) failed: %s !\n", i, strerror(errno));
return -1;
}
ioctl(fd , VIDIOC_QBUF, &buf);
printf("Frame buffer %d: address=%#X, length=%d\n", i, (unsigned int)
framebuf[i].start, framebuf[i].length);
}
// 开始录制
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd, VIDIOC_STREAMON, &type);
// Get frame
ioctl(fd, VIDIOC_DQBUF, &buf);
printf("buf.index=%d\n",buf.index);
// Process the frame
FILE *fp = fopen(CAPTURE_FILE, "w");
fwrite(framebuf[buf.index].start, 1, buf.length, fp);
fclose(fp);
// Re-queen buffer
ioctl(fd, VIDIOC_QBUF, &buf);
// Release the resource
for (i=0; i< 4; i++)
{
munmap(framebuf[i].start, framebuf[i].length);
}
close(fd);
return 0;
}
测试:
[root@localhost test]# modprobe vivi
[root@localhost test]# ./V4L2-APP
driver: vivi
card: vivi
bus_info: vivi-000
version: 00000600
capabilities: 05000001
type: 1
width: 640
height: 480
pixelformat: YUYV
field: 4
bytesperline: 1280
sizeimage: 614400
colorspace: 0
priv: 0
raw_date: ?
Frame buffer 0: address=0XB8040000, length=614400
Frame buffer 1: address=0XB7FAA000, length=614400
Frame buffer 2: address=0XB7F14000, length=614400
Frame buffer 3: address=0XB7E7E000, length=614400
buf.index=0
[root@localhost test]# ls frame.jpg
frame.jpg