网上知识点杂,比较乱,这里整理一下,也开始学习linux下获取摄像头数据,然后(s5pv210)h264硬编码,再封装成rtp包,使用rtsp传输。
1. 打开设备文件。
int fd=open(”/dev/video0″,O_RDWR);
2. 取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。
VIDIOC_QUERYCAP,struct v4l2_capability
3. 选择视频输入,一个视频设备可以有多个视频输入。
VIDIOC_S_INPUT,struct v4l2_input
4. 设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。
VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format
5. 向驱动申请帧缓冲,一般不超过5个。
struct v4l2_requestbuffers
6. 将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。
mmap
7. 将申请到的帧缓冲全部入队列,以便存放采集到的数据.
VIDIOC_QBUF,struct v4l2_buffer
8. 开始视频的采集。
VIDIOC_STREAMON
9. 出队列以取得已采集数据的帧缓冲,取得原始采集数据。
VIDIOC_DQBUF
10. 将缓冲重新入队列尾,这样可以循环采集。
VIDIOC_QBUF
11. 停止视频的采集。
VIDIOC_STREAMOFF
12. 关闭视频设备。
close(fd);
下面的代码是从video0下获取一帧数据,(前提是摄像头支持mjpeg输出,否则若输出为yuv,要先jpeg压缩,这里暂不做)并保存为jpeg图片。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <asm/types.h> #include <linux/videodev2.h> static int do_save(const unsigned char *buf, const int len) { if(!buf) return -EINVAL; int fd = -1; fd = open("cap.jpeg", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if(fd < 0) { perror("open cap.jpeg"); return -1; } if(write(fd, buf, len) < 0) { perror("write to cap.jpeg"); } close(fd); return 0; } #define NB_BUFFER 4 static const char* dev = "/dev/video0"; int devfd; int main(void) { int ret = 0; struct v4l2_capability cap; struct v4l2_format fmt; int width = 640; int height = 480; struct v4l2_requestbuffers rb; int i = 0; struct v4l2_buffer buf; void *mem[NB_BUFFER]; int memlength[NB_BUFFER]; int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; unsigned char *tmpbuffer; int tmpbytesused = 0; /* 1. open */ devfd = open(dev, O_RDWR); if(devfd == -1) { perror("ERROR opening V4L interface"); return -1; } /* 2. get capability */ memset(&cap, 0, sizeof(struct v4l2_capability)); ret = ioctl(devfd, VIDIOC_QUERYCAP, &cap); if(ret < 0) { fprintf(stderr, "Error opening %s: unable to query device.\n", dev); goto end; } if((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { fprintf(stderr, "Error opening %s: video capture not supported.\n", dev); goto end; } if(!(cap.capabilities & V4L2_CAP_STREAMING)) { fprintf(stderr, "%s does not support streaming i/o\n", dev); goto end; } /* 3. set input */ /* 4. set format */ memset(&fmt, 0, sizeof(struct v4l2_format)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = width; fmt.fmt.pix.height = height; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;/* V4L2_PIX_FMT_YUYV */ fmt.fmt.pix.field = V4L2_FIELD_ANY; ret = ioctl(devfd, VIDIOC_S_FMT, &fmt); if(ret < 0) { fprintf(stderr, "Unable to set format: MJPEG res: %dx%d\n", width, height); //FIXME check the format availablility here! goto end; } /* 5. request buffers */ memset(&rb, 0, sizeof(struct v4l2_requestbuffers)); rb.count = NB_BUFFER; rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; rb.memory = V4L2_MEMORY_MMAP; ret = ioctl(devfd, VIDIOC_REQBUFS, &rb); if(ret < 0) { perror("Unable to allocate buffers"); goto end; } /* 6. map buffers */ for(i = 0; i < NB_BUFFER; i++) { memset(&buf, 0, sizeof(struct v4l2_buffer)); buf.index = i; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; ret = ioctl(devfd, VIDIOC_QUERYBUF, &buf); if(ret < 0) { perror("Unable to query buffer"); goto end; } fprintf(stderr, "length: %u offset: %u\n", buf.length, buf.m.offset); mem[i] = mmap(0 /* start anywhere */ , buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, devfd, buf.m.offset); if(mem[i] == MAP_FAILED) { perror("Unable to map buffer"); mem[i] = NULL; goto end; } memlength[i] = buf.length; fprintf(stderr, "Buffer mapped at address %p.\n", mem[i]); } /* 7. queue buffers */ for(i = 0; i < NB_BUFFER; ++i) { memset(&buf, 0, sizeof(struct v4l2_buffer)); buf.index = i; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; ret = ioctl(devfd, VIDIOC_QBUF, &buf); if(ret < 0) { perror("Unable to queue buffer"); goto end; } } /* 8. stream on */ ret = ioctl(devfd, VIDIOC_STREAMON, &type); if(ret < 0) { perror("Unable to start capture"); goto end_unmap; } /* 9. dqbuf */ type = V4L2_BUF_TYPE_VIDEO_CAPTURE; memset(&buf, 0, sizeof(struct v4l2_buffer)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; ret = ioctl(devfd, VIDIOC_DQBUF, &buf); if(ret < 0) { perror("Unable to dequeue buffer"); goto streamoff; } tmpbuffer = (unsigned char *) malloc((size_t)(width * height << 1)); memcpy(tmpbuffer, mem[buf.index], buf.bytesused); tmpbytesused = buf.bytesused; /* 10. qbuf */ ret = ioctl(devfd, VIDIOC_QBUF, &buf); if(ret < 0) { perror("Unable to requeue buffer"); goto free; } do_save(tmpbuffer, tmpbytesused); free: free(tmpbuffer); streamoff: /* 11. stream off */ type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret = ioctl(devfd, VIDIOC_STREAMOFF, &type); if(ret != 0) perror("Unable to stop capture"); end_unmap: for(i = 0; i < NB_BUFFER; i++) if(mem[i] != NULL) munmap(mem[i], memlength[i]); end: /* 12. close */ close(devfd); return ret; }
linux下编译运行,得到cap.jpeg,可直接预览。