昨天拷了一段以前写的在Windows下运行的摄像头录像代码,发现在Ubuntu14.04下这样写有问题:
/****************************/
/*摄像头录像测试程序 */
/****************************/
#include <cv.h>
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
const char g_inPath[] = "in.avi";
const char g_outPath[] = "out.avi";
int main()
{
CvCapture *capture = 0;
int camera_index = -1;
capture = cvCreateCameraCapture(camera_index);
if (!capture)
{
std::cout << "Camera "<<camera_index << " can not open!"<<std::endl;
return -1;
}
IplImage *frame = cvQueryFrame(capture);
double fps = cvGetCaptureProperty(capture,CV_CAP_PROP_FPS);
int width = (int)cvGetCaptureProperty(capture,CV_CAP_PROP_FRAME_WIDTH);
int height = (int)cvGetCaptureProperty(capture,CV_CAP_PROP_FRAME_HEIGHT);
CvSize size = cvSize(width,height);
CvVideoWriter *writer = cvCreateVideoWriter(g_outPath, -1, fps, size);
IplImage *out_frame = cvCreateImage(size,frame->depth,frame->nChannels);
while ((frame = cvQueryFrame(capture)) != NULL)
{
cvCopy(frame, out_frame);
cvWriteFrame(writer,frame);
cvShowImage("Video",out_frame);
char c = cvWaitKey(33);
if (c == 27)
{
break;
}
}
cvReleaseVideoWriter(&writer);
cvReleaseImage(&out_frame);
cvReleaseImage(&frame);
cvReleaseCapture(&capture);
system("pause");
return 0;
}
运行结果:
有时间能运行,有时间报错,没找到原因。网上资料很少,无意中搜到一篇文章:
http://blog.chinaunix.net/uid-26851094-id-3270803.html
接触到了V4L2,沿着前辈的思路入门,先抄个例程,看一下效果
参考:
http://www.linuxidc.com/Linux/2011-03/33020.htm
http://www.linuxidc.com/Linux/2011-03/33021.htm
/****************************/
/*V4L2摄像头获取单幅图片测试程序*/
/****************************/
#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 CLEAR(x) memset(&(x), 0, sizeof(x));
struct buffer
{
void *start;
size_t length;
};
// 摄像头设备名
static char * dev_name = "/dev/video1";
static int fd = -1;
struct buffer * buffers = NULL;
static unsigned int n_buffers = 0;
FILE *file_fd;
static unsigned long file_length;
static unsigned char *file_name;
//
//获取一帧数据
//
static int read_frame(void)
{
struct v4l2_buffer buf;
unsigned int i;
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
// 出列采集的帧缓冲
int ff = ioctl(fd,VIDIOC_DQBUF, &buf);
if (ff < 0)
{
printf("failture \n");
}
assert(buf.index < n_buffers);
// 将其写入文件中
fwrite(buffers[buf.index].start,buffers[buf.index].length, 1, file_fd);
// 再将其入列
ff = ioctl(fd, VIDIOC_QBUF, &buf);
if (ff < 0)
{
printf("failture VIDIOC_QBUF\n");
}
return 1;
}
int main(int argc, char **argv)
{
struct v4l2_capability cap;
struct v4l2_format fmt;
unsigned int i;
enum v4l2_buf_type type;
// 图片文件名
file_fd = fopen("test-mmap.jpg","w");
// 打开设备
fd = open(dev_name, O_RDWR /*required*/ | O_NONBLOCK, 0);
// 获取摄像头参数
ioctl(fd, VIDIOC_QUERYCAP, &cap);
CLEAR(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 640;
fmt.fmt.pix.height = 480;
fmt.fmt.pix.pixelformat = V4L2_FIELD_INTERLACED;
// 设置图像格式
ioctl(fd, VIDIOC_S_FMT, &fmt);
// 计算图片大小
file_length = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
struct v4l2_requestbuffers req;
CLEAR(req);
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
// 申请缓冲,count是申请的数量
ioctl(fd,VIDIOC_REQBUFS,&req);
if (req.count < 2)
{
printf("Insufficient buffer memory\n");
}
// 内存中建立对应的空间
buffers = (buffer *)calloc(req.count, sizeof(*buffers));
for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
{
// 驱动中的一帧
struct v4l2_buffer buf;
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
// 映射用户空间
if (-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf))
{
printf("VIDIOC_QUERYBUF error\n");
}
buffers[n_buffers].length = buf.length;
// 通过mmap建立映射关系
buffers[n_buffers].start = mmap(
NULL, /*start anywhere*/
buf.length,
PROT_READ | PROT_WRITE, /*required*/
MAP_SHARED, /*required*/
fd,
buf.m.offset
);
if (MAP_FAILED == buffers[n_buffers].start)
{
printf("mmap failed\n");
}
}
for (i = 0; i < n_buffers; ++i)
{
struct v4l2_buffer buf;
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
// 申请到的缓冲进入列队
if (-1 == ioctl(fd,VIDIOC_QBUF, &buf))
{
printf("VIDIOC_QBUF failed\n");
}
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
// 开始捕捉图像数据
if (-1 == ioctl(fd, VIDIOC_STREAMON, &type))
{
printf("VIDIOC_STREAMON failed\n");
}
// 这一段涉及到异步IO
for (;;)
{
fd_set fds;
struct timeval tv;
int r;
// 将指定的文件描述符集清空
FD_ZERO(&fds);
// 在文件描述符集合中增加一个新的文件描述符
FD_SET(fd, &fds);
/*Timeout.*/
tv.tv_sec = 2;
tv.tv_usec = 0;
// 判断是否可读(即摄像头是否准备好),tv是定时
r = select(fd + 1, &fds, NULL, NULL, &tv);
if (-1 == r)
{
if( EINTR == errno)
{
continue;
}
printf("select err\n");
}
if (0 == r)
{
fprintf(stderr,"select timeout\n");
exit(EXIT_FAILURE);
}
// 如果可读,执行read_frame()函数,并跳出循环
if (read_frame())
{
break;
}
}
unmap:
for (i = 0; i < n_buffers; ++i)
{
if (-1 == munmap(buffers[i].start, buffers[i].length))
{
printf("munmap error\n");
}
}
close (fd);
fclose (file_fd);
exit(EXIT_SUCCESS);
return 0;
}
运行效果:
报错了,尚不知什么原因,明天继续。