昨天拷了一段以前寫的在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 = ;
int camera_index = -;
capture = cvCreateCameraCapture(camera_index);
if (!capture)
{
std::cout << "Camera "<<camera_index << " can not open!"<<std::endl;
return -;
}
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, -, 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();
if (c == )
{
break;
}
}
cvReleaseVideoWriter(&writer);
cvReleaseImage(&out_frame);
cvReleaseImage(&frame);
cvReleaseCapture(&capture);
system("pause");
return ;
}
運作結果:
有時間能運作,有時間報錯,沒找到原因。網上資料很少,無意中搜到一篇文章:
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 = -;
struct buffer * buffers = NULL;
static unsigned int n_buffers = ;
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 < )
{
printf("failture \n");
}
assert(buf.index < n_buffers);
// 将其寫入檔案中
fwrite(buffers[buf.index].start,buffers[buf.index].length, , file_fd);
// 再将其入列
ff = ioctl(fd, VIDIOC_QBUF, &buf);
if (ff < )
{
printf("failture VIDIOC_QBUF\n");
}
return ;
}
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, );
// 擷取攝像頭參數
ioctl(fd, VIDIOC_QUERYCAP, &cap);
CLEAR(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = ;
fmt.fmt.pix.height = ;
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 = ;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
// 申請緩沖,count是申請的數量
ioctl(fd,VIDIOC_REQBUFS,&req);
if (req.count < )
{
printf("Insufficient buffer memory\n");
}
// 記憶體中建立對應的空間
buffers = (buffer *)calloc(req.count, sizeof(*buffers));
for (n_buffers = ; 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 (- == 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 = ; 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 (- == ioctl(fd,VIDIOC_QBUF, &buf))
{
printf("VIDIOC_QBUF failed\n");
}
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
// 開始捕捉圖像資料
if (- == 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 = ;
tv.tv_usec = ;
// 判斷是否可讀(即攝像頭是否準備好),tv是定時
r = select(fd + , &fds, NULL, NULL, &tv);
if (- == r)
{
if( EINTR == errno)
{
continue;
}
printf("select err\n");
}
if ( == r)
{
fprintf(stderr,"select timeout\n");
exit(EXIT_FAILURE);
}
// 如果可讀,執行read_frame()函數,并跳出循環
if (read_frame())
{
break;
}
}
unmap:
for (i = ; i < n_buffers; ++i)
{
if (- == munmap(buffers[i].start, buffers[i].length))
{
printf("munmap error\n");
}
}
close (fd);
fclose (file_fd);
exit(EXIT_SUCCESS);
return ;
}
運作效果:
報錯了,尚不知什麼原因,明天繼續。