采用V4L2实现摄像头调用

#include <iostream>
#include <unistd.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <cstdio>
#include <fcntl.h>
#include <cstring>
#include <sys/mman.h>//for ying she
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <vector>
#include <pthread.h>

using namespace cv;
using namespace std;

unsigned char *mptr[2];//保存映射后用户空间的首地址
unsigned int length[2];
int ret;
int fd;
typedef struct{
    Mat img;
}mystruct;

void* window1(void* args)
{
    //pthread_detach(pthread_self());
    mystruct *a = (mystruct *) args;

    imshow("img1",a->img);
    return NULL;
}

void* window2(void* args)
{
    //pthread_detach(pthread_self());
    mystruct *a = (mystruct *) args;
    //if(waitKey(10)=='f')
    {
        imshow("img2",a->img);
    }
    return NULL;
}
int main() {
    Mat img;
    mystruct arg;
    namedWindow("img1",WINDOW_AUTOSIZE);
    namedWindow("img2",WINDOW_AUTOSIZE);
    pthread_t th1;//定义一个新的线程
    pthread_t th2;

    /*  1.open the device  */
    fd = open("/dev/video0",O_RDWR);
    if (fd < 0 )
    {
        perror("open fail\n");
        return -1;
    }

    /*  2.get format  */
    struct v4l2_fmtdesc v4fmt;
    v4fmt.index = 0;// ditterent from the video
    v4fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(fd, VIDIOC_ENUM_FMT,&v4fmt);// ioctl(fd , command , struct related to the command)
    if (ret < 0 )
    {
        perror("get fail\n");
        return -1;
    }
    printf("index=%d\n",v4fmt.index);
    printf("flags=%d\n",v4fmt.flags);
    printf("description=%s\n",v4fmt.description);
    unsigned char *p=(unsigned char *)&v4fmt.pixelformat;
    printf("pixelformat=%c%c%c%c\n",p[0],p[1],p[2],p[3]);
    printf("reserved=%d\n",v4fmt.reserved[0]);


    /*  3.set capturing format  */
    struct v4l2_format vfmt;
    vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    vfmt.fmt.pix.width = 640;
    vfmt.fmt.pix.height = 480;
    vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;//set capturing format
    ret = ioctl(fd,VIDIOC_S_FMT,&vfmt);
    if (ret < 0)
    {
        perror("set format fail\n");
    }
    memset(&vfmt,0,sizeof(vfmt));
    vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(fd,VIDIOC_G_FMT,&vfmt);
    if (ret < 0)
    {
        perror("get format fail\n");
    }
    if (vfmt.fmt.pix.width == 640 && vfmt.fmt.pix.height == 480 && vfmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
    {
        printf("set succeed\n");
    }else
    {
        printf("set failed\n");
    }

    /*  4.apply nei he kong jian  */
    struct v4l2_requestbuffers reqbuffer;
    reqbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    reqbuffer.count = 2;//apply 4 huan chong qv
    reqbuffer.memory = V4L2_MEMORY_MMAP;//set yin she fang shi
    ret = ioctl(fd,VIDIOC_REQBUFS,&reqbuffer);
    if (ret < 0)
    {
        perror("apply fail\n");
    }

    struct v4l2_buffer mapbuffer;
    mapbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    for(int i=0;i<2;i++)
    {
        mapbuffer.index = i;
        ret = ioctl(fd,VIDIOC_QUERYBUF,&mapbuffer);//从内核空间中查询一个空间做映射
        if (ret < 0)
        {
            perror("query fail\n");
        }

        mptr[i] = (unsigned char *)mmap(NULL,mapbuffer.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,mapbuffer.m.offset);
        length[i] = mapbuffer.length;
        ///通知使用完毕,放回去
        ret = ioctl(fd,VIDIOC_QBUF,&mapbuffer);//不要mapbuffer了,还回去
        if (ret < 0)
        {
            perror("return fail\n");
        }
    }

    /*  6.start capturing  */
    //VIDIOC_DQBUF:告诉内核我要某一个数据,内核不可以修改
    //VIDIOC_QBUF:告诉内核我已经使用完毕
    //VIDIOC_STREAMON:开始采集,数据到队列中
    //VIDIOC_STREAMOFF:停止采集,不再向队列中写数据
    int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(fd,VIDIOC_STREAMON,&type);
    if (ret < 0)
    {
        perror("start fail\n");
    }

    while (1)
    {
        //从队列中提取一帧数据
        struct v4l2_buffer readbuffer;
        readbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        readbuffer.index = 6;//无效,下一行代码会设置index的值
        ret = ioctl(fd,VIDIOC_DQBUF,&readbuffer);
        if (ret < 0)
        {
            perror("extract fail\n");
        }

        vector<char>vec_data(mptr[readbuffer.index],mptr[readbuffer.index]+readbuffer.length);
        img = imdecode(vec_data,IMREAD_COLOR);
        arg.img=img;

        pthread_create(&th1,NULL, window1,&arg);//正式创建
        pthread_create(&th2,NULL, window2,&arg);//正式创建
        //通知内核已经使用完毕
        ret = ioctl(fd,VIDIOC_QBUF,&readbuffer);
        if (ret < 0)
        {
            perror("return fail\n");
        }
        pthread_join(th1,NULL);
        pthread_join(th2,NULL);
        if (waitKey(30) == 'l')
        {
            break;
        }

    }

    //pthread_join(th1,NULL);
    //pthread_join(th2,NULL);
    /*  7.stop capturing  */
    ret = ioctl(fd,VIDIOC_STREAMOFF,&type);
    if (ret < 0)
    {
        perror("stop fail\n");
    }

    /*  8.release yin she  */
    for (int i = 0; i< 4; i++)
    {
        munmap(mptr[i],length[i]);
    }
    /*  close the device  */
    close(fd);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值