我正在研究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;
}
由于我对捕获和流式传输视频的了解有限,所以我非常感谢您的帮助。