V4L2摄像头获取图片

昨天拷了一段以前写的在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;

}

运行效果:
这里写图片描述

报错了,尚不知什么原因,明天继续。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值