您尚未登录。

楼主 #1 2020-09-18 21:42:47

cijliu
Moderator
注册时间: 2019-06-13
已发帖子: 59
积分: 56

【Dopi】在HI3516EV200上使用V4L2采集摄像头数据

海思摄像头架构并不支持标准Linux的V4L2架构,这对摄像头应用十分不友好,MPP学习曲线较为陡峭,为了大家能够方便获取摄像头数据,编写了为了兼容海思摄像头的V4L2驱动和中间件程序(暂时只支持开发板上的显示屏320x240像素),加载后就可以正常使用V4L2进行摄像头应用开发。
在使用出厂固件环境下进行如下操作

#hisilicon media driver
cd /ko && ./load3516ev200 -i -sensor imx307

#spi lcd driver
insmod /lib/modules/4.9.37/fb_ili9341.ko
modprobe fbtft_device name=ilitek,ili9341 gpios=reset:40,dc:70 busnum=0 mode=0 rotate=90 

#v4l2
cd -
insmod hi3516ev200_v4l2.ko 
./hi3516ev200_dopi_media /dev/video0 &
./app  

最终,V4L2测试程序将会把摄像头数据呈现在LCD屏幕上
附件:
Dopi V4L2中间件驱动

离线

楼主 #2 2020-09-23 09:35:34

cijliu
Moderator
注册时间: 2019-06-13
已发帖子: 59
积分: 56

Re: 【Dopi】在HI3516EV200上使用V4L2采集摄像头数据

使用V4L2接口保存一帧YUV图像开发示例

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <string.h>
#include <sys/mman.h>
#include <assert.h>
#include <poll.h>
#include <errno.h>
#include <stdlib.h>
#define VIDEO_NAME  "/dev/video0"
struct videobuffer{
    unsigned int length;
    void* start;
};

int main()
{
    //open video
    int dev = open(VIDEO_NAME,  O_RDWR | O_NONBLOCK, 0);
    if(dev <0 ){
        printf("open video0 fail.\n");
        return -1;
    }


    //query capability
    struct v4l2_capability cap;
    ioctl(dev, VIDIOC_QUERYCAP, &cap);
    printf("--------------capability------------------\n");
    printf("driver:%s    \ncard:%s   \ncapabilities:%x\n",cap.driver,cap.card,cap.capabilities);

    //set and get format
    struct v4l2_fmtdesc fmtdesc;
    int ret;
    int i;
    memset(&fmtdesc, 0, sizeof(fmtdesc));
    fmtdesc.index = 0;
    fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    printf("-------------VIDIOC_ENUM_FMT--------------\n");
    while((ioctl(dev, VIDIOC_ENUM_FMT, &fmtdesc)) != -1)
    {
        printf("index:%d   \npixelformat:%c%c%c%c  \ndescription:%s\n",fmtdesc.index, fmtdesc.pixelformat&0xff,(fmtdesc.pixelformat>>8)&0xff,(fmtdesc.pixelformat>>16)&0xff,
        (fmtdesc.pixelformat>>24)&0xff,fmtdesc.description);
        fmtdesc.index++;
    }

    int width = 320, height = 240;
    struct v4l2_format format;
    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    format.fmt.pix.width = width;
    format.fmt.pix.height = height;
    format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;  // 设置为yuyv格式数据
    format.fmt.pix.field = V4L2_FIELD_INTERLACED;
    ret = ioctl(dev, VIDIOC_S_FMT, &format);
    if(ret < 0){
        printf("VIDIOC_S_FMT fail\n");
        return -1;
    }
    memset(&format, 0, sizeof(format));
    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(dev, VIDIOC_G_FMT, &format);
    if(ret < 0)
    {
        printf("VIDIOC_G_FMT fail\n");
        return -1;
    }
    printf("-----------------VIDIOC_G_FMT----------------------\n");
    printf("width:%d   \nheight:%d   \ntype:%x   pixelformat:%c%c%c%c\n",format.fmt.pix.width,format.fmt.pix.height,
        format.type,format.fmt.pix.pixelformat&0xff,(format.fmt.pix.pixelformat>>8)&0xff,(format.fmt.pix.pixelformat>>16)&0xff,
        (format.fmt.pix.pixelformat>>24)&0xff);

    //init mmap
    struct videobuffer framebuf;
    struct v4l2_requestbuffers reqbuf;

    reqbuf.count = 1;
    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    reqbuf.memory = V4L2_MEMORY_MMAP;
    ret = ioctl(dev, VIDIOC_REQBUFS, &reqbuf);
    if(0 != ret){
        printf("VIDIOC_REQBUFS fail\n");
        return -1;
    }
    //v4l2_buffer
    printf("----------------mmap----------------\n");

    struct v4l2_buffer buf;
    memset(&buf, 0, sizeof(buf));
    buf.index = 1;
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    ret = ioctl(dev, VIDIOC_QUERYBUF, &buf);

    framebuf.length = buf.length;
    framebuf.start = mmap(NULL, buf.length, PROT_READ|PROT_WRITE, 
        MAP_SHARED, dev, buf.m.offset);
    if(framebuf.start == MAP_FAILED){
        perror("mmap fail.\n");
        return -1;
    }
    printf("start:%p  length:%d\n",framebuf.start,framebuf.length);


    for(i=0;i < 1; i++){
        memset(&buf, 0, sizeof(buf));
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        buf.index = i;
        ret = ioctl(dev, VIDIOC_QBUF, &buf);
        if(0 != ret){
            perror("VIDIOC_QBUF fail.\n");
            return -1;
        }
    }

    enum v4l2_buf_type type;
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(dev, VIDIOC_STREAMON, &type);
    //usleep(500000);
    struct pollfd pollfd;
    for(;;i++){

        memset(&pollfd, 0, sizeof(pollfd));
        pollfd.fd = dev;
        pollfd.events = POLLIN;
        ret = poll(&pollfd, 1, 800);
        printf("poll %d i=%d\n",pollfd.revents, i);
        if(-1 == ret){
            perror("VIDIOC_QBUF fail.\n");
            return -1;
        }else if(0 == ret){
            printf("poll time out\n");
            continue;
        }
        break;
    }
    //printf("-------------poll success---------------\n");
    // static struct v4l2_buffer buf;

    if(pollfd.revents & POLLIN){
        memset(&buf, 0, sizeof(buf));
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        ret = ioctl(dev, VIDIOC_DQBUF, &buf);
        if(0 != ret){
            perror("VIDIOC_QBUF fail.\n");
            return -1;
        }
    }
    printf("-------------capture success---------------\n");

    FILE *fp = fopen("./yuv.yuv", "wb+");
    loff_t pos = 0;
    fwrite((char*)framebuf.start, 1, buf.length, fp);
    fclose(fp);
    close(dev);
    return 0;
}

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn