有可能在c++中使用树莓派v4l2相机获得良好的FPS吗

Is it possible to get good FPS using Raspberry Pi camera v4l2 in c++?

本文关键字:相机 FPS v4l2 c++ 有可能      更新时间:2023-10-16

我正试图使用带有Raspberry Pi相机的官方V4L2驱动程序在Raspberrry Pi上播放视频,该驱动程序来自raspbian上的C++(2015-02版本),但我遇到了低FPS问题。

目前,我只是创建一个窗口并将缓冲区复制到屏幕上(大约需要30ms),而select()大约需要140ms(总共5-6 fps)。我还试着睡100毫秒,它将select()时间减少了类似的量(导致相同的fps)。CPU负载约为5-15%。

我还尝试从控制台(或system())更改驱动程序的fps,但它只能向下工作(例如,如果我将驱动程序fps设置为1fps,我会得到1fps;但如果我将其设置为90fps,即使驱动程序确认将其设置成90fps也会得到5-6fps)。此外,当查询FPS模式中使用的分辨率时,我得到90fps。

我包括了与V4L2相关的代码部分(不同部分之间省略了代码):

//////////////////
// Open device
//////////////////
mFD = open(mDevName, O_RDWR | O_NONBLOCK, 0);
if (mFD == -1) ErrnoExit("Open device failed");
//////////////////
// Setup format
//////////////////
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
Xioctl(VIDIOC_G_FMT, &fmt);
mImgWidth = fmt.fmt.pix.width;
mImgHeight = fmt.fmt.pix.height;
cout << "width=" << mImgWidth << " height=" << mImgHeight << "nbytesperline=" << fmt.fmt.pix.bytesperline << " sizeimage=" << fmt.fmt.pix.sizeimage << "n";
// For some reason querying the format always sets pixelformat to JPEG
//  no matter the input, so set it back to YUYV
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
if (Xioctl(VIDIOC_S_FMT, &fmt) == -1)
{
cout << "Set video format failed : " << strerror(errno) << "n";
}
//////////////////
// Setup streaming
//////////////////
struct v4l2_requestbuffers req;
memset(&req, 0, sizeof(req));
req.count = 20;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (-1 == Xioctl(VIDIOC_REQBUFS, &req))
{
ErrnoExit("Reqbufs");
}
if (req.count < 2)
throw "Not enough buffer memory !";
mNBuffers = req.count;
mBuffers = new CBuffer[mNBuffers];
if (!mBuffers) throw "Out of memory !";
for (unsigned int i = 0; i < mNBuffers; i++)
{
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (-1 == Xioctl(VIDIOC_QUERYBUF, &buf))
ErrnoExit("Querybuf");
mBuffers[i].mLength = buf.length;
mBuffers[i].pStart = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, mFD, buf.m.offset);
if (mBuffers[i].pStart == MAP_FAILED)
ErrnoExit("mmap");
}
//////////////////
// Start streaming
//////////////////
unsigned int i;
enum v4l2_buf_type type;
struct v4l2_buffer buf;
for (i = 0; i < mNBuffers; i++)
{
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (-1 == Xioctl(VIDIOC_QBUF, &buf))
ErrnoExit("QBUF");
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1==Xioctl(VIDIOC_STREAMON, &type))
ErrnoExit("STREAMON");

主循环中的最后两部分:

//////////////////
// Get frame
//////////////////
FD_ZERO(&fds);
FD_SET(mFD, &fds);
tv.tv_sec = 3;
tv.tv_usec = 0;
struct timespec t0, t1;
clock_gettime(CLOCK_REALTIME, &t0);
// This line takes about 140ms which I don't get
r = select(mFD + 1, &fds, NULL, NULL, &tv);
clock_gettime(CLOCK_REALTIME, &t1);
cout << "select time : " << ((float)(t1.tv_sec - t0.tv_sec))*1000.0f + ((float)(t1.tv_nsec - t0.tv_nsec))/1000000.0f << "n";
if (-1 == r)
{
if (EINTR == errno)
continue;
ErrnoExit("select");
}
if (r == 0)
throw "Select timeoutn";
// Read the frame
//~ struct v4l2_buffer buf;
memset(&mCurBuf, 0, sizeof(mCurBuf));
mCurBuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
mCurBuf.memory = V4L2_MEMORY_MMAP;
// DQBUF about 2ms
if (-1 == Xioctl(VIDIOC_DQBUF, &mCurBuf))
{
if (errno == EAGAIN) continue;
ErrnoExit("DQBUF");
}
clock_gettime(CLOCK_REALTIME, &mCaptureTime);
// Manage frame in mBuffers[buf.index]
mCurBufIndex = mCurBuf.index;
break;
}
//////////////////
// Release frame
//////////////////
if (-1 == Xioctl(VIDIOC_QBUF, &mCurBuf))
ErrnoExit("VIDIOC_QBUF during mainloop");

我一直在研究使用picamera的各种方法,我几乎不是专家,但默认的相机设置似乎是阻碍你的因素。有许多模式和开关。我不知道它们是否通过ioctl暴露,也不知道是如何暴露的,我才刚刚开始。但我不得不使用一个名为v4l-ctl的程序来为我想要的模式做好准备。深入研究这个源代码和一些代码提升应该会让你取得伟大成就。哦,我怀疑select调用是个问题,它只是在等待描述符,而描述符的可读性很慢。根据模式等,可能会强制等待自动曝光等。编辑:我的意思是说"默认设置",因为你已经更改了一些。还有一些规则没有编入驱动程序。

像素格式很重要。我遇到了类似的低帧速率问题,我花了一些时间在Go和C++中使用V4L2 API测试我的程序。我发现,Rpi摄像头模块与H.264/MJPG像素格式有很好的加速。我可以在640*480的速度下轻松获得60fps,与YUYV/RGB等非压缩格式相同。但是JPEG运行速度非常慢。即使是320*240,我也只能得到4英尺/秒。我还发现,与H.264/MJPG的500mA相比,JPEG的电流更高(>700mA)。