使用mmap环形缓冲区捕获v4l2相机是否有助于跟踪应用程序

时间:2017-04-13 09:00:15

标签: c++ video-capture v4l2

我正在研究v4l2 API,用于从嵌入式平台上的原始传感器捕获图像。我的捕获例程与[1]上的示例有关。建议的流式传输方法是使用mmaped缓冲区作为环形缓冲区 对于初始化,使用带有VIDIOC_REQBUFS标识符的ioctl请求缓冲区(默认= 4个缓冲区)。随后,它们使用VIDIOC_QBUF排队。整个流程序在此处描述[2]。一旦流启动,驱动程序就会用数据填充排队的缓冲区。 v4l2_buffer结构的时间戳表示捕获第一个字节的时间,在我的情况下,缓冲区之间的时间间隔约为8.3毫秒(= 120fps)。到目前为止一切顺利。
现在我对环形缓冲区的期望是新的捕获以循环方式自动覆盖旧的。但这不是发生的事情。仅当缓冲区在出列(VIDIOC_DQBUF)并进行处理(去马赛克,跟踪步骤,...)后再次排队(VIDIOC_QBUF)时,才会将新帧分配给缓冲区。如果我确实满足时序条件(处理<8.3毫秒),我不会在出列时获得最新捕获的帧,而是最早捕获的帧(根据FIFO),因此在当前帧之前3x8.3毫秒。如果不满足时序条件,则时间跨度会变得更大,因为缓冲区不会被覆盖。

所以我有几个问题:
1.这个跟踪应用程序是否有理由使用环形缓冲区,因为我真的不需要帧历史记录?我当然对此表示怀疑,但是通过使用建议的mmap方法,驱动程序通常需要最少量的缓冲区来请求 2.一个单独的线程是否应该连续DQBUF和QBUF完成缓冲区覆盖?怎么能实现呢? 3.作为一种解决方法,可能会在每次捕获时将所有缓冲区出列并重新排队,但这听起来不对。有没有更多实时捕获和流媒体经验的人可以指出“正确”的方式去哪? 4.目前,我正在进行DQBUF和QBUF之间的预处理步骤(去马赛克)以及之后的跟踪步骤。是否应该在再次调用QBUF之前执行跟踪步骤?

因此主代码基本上在while循环中执行Capture()和Track()。 Capture例程如下所示:

cv::Mat v4l2Camera::Capture( size_t timeout ) { 

    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(mFD, &fds);

    struct timeval tv;

    tv.tv_sec  = 0;
    tv.tv_usec = 0;

    const bool threaded = true; //false;

    // proper register settings
    this->format2registerSetting();
    //

    if( timeout > 0 )
    {
        tv.tv_sec  = timeout / 1000;
        tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
    }

    //
    const int result = select(mFD + 1, &fds, NULL, NULL, &tv);


    if( result == -1 ) 
    {
        //if (EINTR == errno)
        printf("v4l2 -- select() failed (errno=%i) (%s)\n", errno, strerror(errno));
        return cv::Mat();
    }
    else if( result == 0 )
    {
    if( timeout > 0 )
        printf("v4l2 -- select() timed out...\n");  
        return cv::Mat(); // timeout, not necessarily an error      (TRY_AGAIN)
    }

    // dequeue input buffer from V4L2
    struct v4l2_buffer buf;
    memset(&buf, 0, sizeof(v4l2_buffer));

    buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;  //V4L2_MEMORY_USERPTR;

    if( xioctl(mFD, VIDIOC_DQBUF, &buf) < 0 )
    {
        printf("v4l2 -- ioctl(VIDIOC_DQBUF) failed (errno=%i) (%s)\n", errno, strerror(errno));
        return cv::Mat();
    }

    if( buf.index >= mBufferCountMMap )
    {
        printf("v4l2 -- invalid mmap buffer index (%u)\n", buf.index);
        return cv::Mat();
    }

    // emit ringbuffer entry
    printf("v4l2 -- recieved %ux%u video frame (index=%u)\n", mWidth, mHeight, (uint32_t)buf.index);

    void* image_ptr = mBuffersMMap[buf.index].ptr;

    // frame processing (& tracking step)
    cv::Mat demosaic_mat = demosaic(image_ptr,mSize,mDepth,1);

    // re-queue buffer to V4L2
    if( xioctl(mFD, VIDIOC_QBUF, &buf) < 0 )
        printf("v4l2 -- ioctl(VIDIOC_QBUF) failed (errno=%i) (%s)\n", errno, strerror(errno));

    return demosaic_mat;
}

由于我对捕获和流式传输视频的了解有限,所以我非常感谢您的帮助。

0 个答案:

没有答案