一、内容简介
没玩过摄像头,做项目需要在网上找了好长时间没有很合适的,经过自己修改最终实现了摄像头传视频!其实传视频的原理就是一帧一帧的传图片,所以需要获取图片的内容信息和内容长度的信息。再此设置了两个接口,定义了两个变量供主函数调用。
二、camera.c
#include "camera.h" typedef struct VideoBuffer { void *start; size_t length; } VideoBuffer; int cam_len; char cam_buf[500*1024] = {'\0'}; sem_t rt, dt;//定义两个信号量 int camera() { int i, ret; // 打开设备 int fd; fd = open(CAMERA_DEVICE, O_RDWR, 0); if (fd < 0) { printf("Open %s failed\n", CAMERA_DEVICE); return -1; } // 获取驱动信息 struct v4l2_capability cap; ret = ioctl(fd, VIDIOC_QUERYCAP, &cap); if (ret < 0) { printf("VIDIOC_QUERYCAP failed (%d)\n", ret); return ret; } // Print capability infomations printf("Capability Informations:\n"); printf(" driver: %s\n", cap.driver); printf(" card: %s\n", cap.card); printf(" bus_info: %s\n", cap.bus_info); printf(" version: X\n", cap.version); printf(" capabilities: X\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_MJPEG;//设置视频采集格式 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; ret = ioctl(fd, VIDIOC_S_FMT, &fmt); if (ret < 0) { printf("VIDIOC_S_FMT failed (%d)\n", ret); return ret; } // 获取视频格式 ret = ioctl(fd, VIDIOC_G_FMT, &fmt); if (ret < 0) { printf("VIDIOC_G_FMT failed (%d)\n", ret); return ret; } // Print Stream Format printf("Stream Format Informations:\n"); printf(" type: %d\n", fmt.type); printf(" width: %d\n", fmt.fmt.pix.width); printf(" height: %d\n", fmt.fmt.pix.height); char fmtstr[8]; memset(fmtstr, 0, 8); memcpy(fmtstr, &fmt.fmt.pix.pixelformat, 4); printf(" pixelformat: %s\n", fmtstr); 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_control ctrl; ctrl.id = V4L2_CID_EXPOSURE_AUTO; ret = ioctl(fd, VIDIOC_G_CTRL, &ctrl); // 请求分配内存 struct v4l2_requestbuffers reqbuf; reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; reqbuf.count = BUFFER_COUNT; reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; reqbuf.memory = V4L2_MEMORY_MMAP; ret = ioctl(fd , VIDIOC_REQBUFS, &reqbuf); if(ret < 0) { printf("VIDIOC_REQBUFS failed (%d)\n", ret); return ret; } // 获取空间 VideoBuffer* buffers = calloc( reqbuf.count, sizeof(*buffers) ); 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; ret = ioctl(fd , VIDIOC_QUERYBUF, &buf); if(ret < 0) { printf("VIDIOC_QUERYBUF (%d) failed (%d)\n", i, ret); return ret; } // mmap buffer buffers[i].length = buf.length; buffers[i].start = (char *) mmap(0, buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, buf.m.offset); if (buffers[i].start == MAP_FAILED) { printf("mmap (%d) failed: %s\n", i, strerror(errno)); return -1; } // Queen buffer ret = ioctl(fd , VIDIOC_QBUF, &buf); if (ret < 0) { printf("VIDIOC_QBUF (%d) failed (%d)\n", i, ret); return -1; } printf("Frame buffer %d: address=0x%x, length=%d\n", i, (unsigned int)buffers[i].start, buffers[i].length); } // 开始录制 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret = ioctl(fd, VIDIOC_STREAMON, &type); if (ret < 0) { printf("VIDIOC_STREAMON failed (%d)\n", ret); return ret; } while(1){ //读取缓存、、读取一帧图片信息存到cam_len、cam_buf ret = ioctl(fd, VIDIOC_DQBUF, &buf); if (ret < 0) { printf("VIDIOC_DQBUF failed (%d)\n", ret); return ret; } //sem_wait(&rt);//线程同步,先获取一帧再发一帧 cam_len = buf.length; memcpy(cam_buf,buffers[buf.index].start,buf.length);//内容为二进所以需要memcpy函数 //sem_post(&dt);//线程同步 //释放缓存 ret = ioctl(fd, VIDIOC_QBUF, &buf); if (ret < 0) { printf("VIDIOC_QBUF failed (%d)\n", ret); return ret; } } // Release the resource for (i=0; i< 4; i++) { munmap(buffers[i].start, buffers[i].length); } close(fd); printf("Camera test Done.\n"); return 0; }
三、camera.h
#ifndef _CAMERA_H #define _CAMERA_H #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> #include <pthread.h> #include <semaphore.h> #define CAMERA_DEVICE "/dev/video0" #define CAPTURE_FILE "QY.jpg" #define VIDEO_WIDTH 640 #define VIDEO_HEIGHT 480 #define VIDEO_FORMAT V4L2_PIX_FMT_YUYV #define BUFFER_COUNT 4 extern int cam_len; extern char cam_buf[500*1024]; extern sem_t rt;//定义两个信号量 extern sem_t dt; int camera(); #endif