微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

v4l2 简单应用——性能问题

如何解决v4l2 简单应用——性能问题

我有一个非常简单的设置,其中连接到 Pi Zero 的相机由外部信号触发。

问题:我的代码使用 v4l2 时可实现的帧速率为

使用 raspivid 1920x1080 @ 50fps 可以正常工作(使用 -pts 进行测试以保存时间码)。相反,我的代码永远不会以 50Hz 的频率使缓冲区出列。在每约 600 毫秒接收帧之前,我必须将触发率降低到 5Hz!看起来我仍然只接收每第三帧。返回的帧缓冲区总是跳过一个索引:

new frame 0: 3110400
time diff 0.6006

new frame 2: 3110400
time diff 0.6006

new frame 4: 3110400
time diff 0.600601

new frame 6: 3110400
time diff 0.6006

您可以在下面找到我的代码(曝光设置,...已删除

问题:你能告诉我可能是什么问题吗?该程序除了使缓冲区出队和入队外什么都不做,因此性能应该不是问题。

#define NB_BUFFER 10

int main(int argc,char *argv[])
{
    int exposure = 50;
    int rows = 1080;
    int cols = 1920;
    
    if(argc > 1){
        exposure= atoi(argv[1]);
    }
    if(argc > 3){
        cols=atoi(argv[2]);
        rows=atoi(argv[3]);
    }


    struct vdIn vdin;
    struct vdIn *vd = &vdin;
    
    if((vd->fd = open("/dev/video0",O_RDWR)) < 0){
        perror("open");
        exit(1);
    }

    if(ioctl(vd->fd,VIdioC_QUERYCAP,&vd->cap) < 0){
        perror("VIdioC_QUERYCAP");
        exit(1);
    }

    if(!(vd->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)){
        fprintf(stderr,"The device does not handle single-planar video capture.\n");
        exit(1);
    }

    vd->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    vd->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;//V4L2_PIX_FMT_BGR24;
    vd->fmt.fmt.pix.width = cols; 
    vd->fmt.fmt.pix.height = rows;

    if(ioctl(vd->fd,VIdioC_S_FMT,&vd->fmt) < 0){
        perror("VIdioC_S_FMT");
        exit(1);
    }
    
    struct v4l2_control control;
    
    
    control.id = V4L2_CID_EXPOSURE_AUTO ;
    control.value = V4L2_EXPOSURE_MANUAL;
    if(ioctl(vd->fd,VIdioC_S_CTRL,&control) < 0){
        perror("VIdioC_S_CTRL EXPOSURE MANUAL");
        exit(1);
    }
    
    .... iso manual,line frequency off,set exposure,auto whitebalance off
     

    vd->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    vd->rb.memory = V4L2_MEMORY_MMAP;
    vd->rb.count = NB_BUFFER;

    if(ioctl(vd->fd,VIdioC_REQBUFS,&vd->rb) < 0){
        perror("VIdioC_REQBUFS");
        exit(1);
    }
    

    
    
    int ret;
    /* map the buffers */
    struct v4l2_buffer buf;
    for (int i = 0; i < NB_BUFFER; i++) {
        memset (&vd->buf,sizeof (struct v4l2_buffer));
        vd->buf.index = i;
        vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        vd->buf.memory = V4L2_MEMORY_MMAP;
        ret = ioctl (vd->fd,VIdioC_QUERYBUF,&vd->buf);
        if (ret < 0) {
            fprintf (stderr,"Unable to query buffer (%d).\n",errno);
            return -1;
        }
        std::cout << "buf len " << vd->buf.length<<std::endl;
        vd->mem[i] = mmap (0 /* start anywhere */,vd->buf.length,PROT_READ,MAP_SHARED,vd->fd,vd->buf.m.offset);
        if (vd->mem[i] == MAP_Failed) {
            fprintf (stderr,"Unable to map buffer (%d)\n",errno);
            return -1;
        }

    }
  /* Queue the buffers. */
    for (int i = 0; i < NB_BUFFER; ++i) {
        memset (&vd->buf,VIdioC_QBUF,"Unable to queue buffer (%d).\n",errno);
            return -1;
        }
    }

    // Activate streaming
    int type = vd->fmt.type;
    if(ioctl(vd->fd,VIdioC_STREAMON,&type) < 0){
        perror("VIdioC_STREAMON");
        exit(1);
    }

    bool capture_is_running = true;
    double lastTimestamp=0;
    
    while(capture_is_running){
        
            
        memset (&vd->buf,sizeof (struct v4l2_buffer));
        vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        vd->buf.memory = V4L2_MEMORY_MMAP;
        
        std::cout << "try to dequeue" << std::endl;
        
        ret = ioctl (vd->fd,VIdioC_DQBUF,"Unable to dequeue buffer (%d).\n",errno);
            return -1;
        }
        
        cout << "new frame "<<vd->buf.index<<": "<< vd->buf.bytesused << endl;
        
        double timestamp = vd->buf.timestamp.tv_sec + vd->buf.timestamp.tv_usec/1000000.;
        double timeDiff = timestamp - lastTimestamp;
        lastTimestamp = timestamp;
        std::cout << "time diff " << timeDiff << std::endl;
        
        
        ret = ioctl (vd->fd,&vd->buf);
            if (ret < 0) {
            fprintf (stderr,"Unable to requeue buffer (%d).\n",errno);
            return -1;
        }
    }

    // Deactivate streaming
    if(ioctl(vd->fd,VIdioC_STREAMOFF,&type) < 0){
        perror("VIdioC_STREAMOFF");
        exit(1);
    }

    close(vd->fd);
    return EXIT_SUCCESS;

    return 0;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。