简体   繁体   English

是否有可能在c ++中使用Raspberry Pi相机v4l2获得良好的FPS?

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

I'm trying to stream video on a Raspberry Pi using the official V4L2 driver with the Raspberry Pi camera, from C++ on raspbian (2015-02 release), and I'm having low FPS issues. 我正在尝试使用带有Raspberry Pi相机的官方V4L2驱动程序在Raspberry Pi上流式传输视频,来自C ++ on raspbian(2015-02发布),我的FPS问题很少。

Currently I'm just creating a window and copying the buffer to the screen (which takes about 30ms) whereas the select() takes about 140ms (for a total of 5-6 fps). 目前我只是创建一个窗口并将缓冲区复制到屏幕(大约需要30ms),而select()需要大约140ms(总共5-6 fps)。 I also tried sleeping for 100ms and it decreases the select() time by a similar amount (resulting in the same fps). 我也尝试睡眠100毫秒,它将select()时间减少了相似的量(导致相同的fps)。 CPU load is about 5-15%. CPU负载约为5-15%。

I also tried changing the driver fps from console (or system() ) but it only works downwards (for example, if I set the driver fps to 1fps, I'll get 1fps but if I set it to 90fps I still get 5-6fps, even though the driver confirms setting it to 90fps). 我也尝试从控制台(或system() )更改驱动程序fps但它只能向下工作(例如,如果我将驱动程序fps设置为1fps,我将获得1fps但如果我将其设置为90fps我仍然得到5- 6fps,即使驱动程序确认将其设置为90fps)。 Also, when querying FPS modes for the used resolution I get 90fps. 此外,当查询使用分辨率的FPS模式时,我得到90fps。

I included the parts of the code related to V4L2 (code omitted between different parts) : 我包含了与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");

And the last two parts in the main loop : 主循环中的最后两部分:

//////////////////
// 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 timeout\n";

    // 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");

I have been looking at the various methods of using the picamera and I'm hardly an expert, but it would seem that the default camera settings are what's holding you back. 我一直在研究使用picamera的各种方法,我几乎不是专家,但似乎默认的相机设置是阻碍你的。 There are many modes and switches. 有许多模式和开关。 I don't know if they are exposed through ioctls or how yet, I just started. 我不知道他们是通过ioctls暴露还是如何暴露,我刚刚开始。 But I had to use a program called v4l-ctl to get things ready for the mode I wanted. 但我不得不使用一个名为v4l-ctl的程序来为我想要的模式做好准备。 A deep look at that source and some code lifting should let you achieve greatness. 深入了解该来源和一些代码提升应该可以让您实现伟大。 Oh, and I doubt the select call is an issue, it's simply waiting on the descriptor which is slow to become readable. 哦,我怀疑选择调用是一个问题,它只是在等待描述符,它很慢变得可读。 Depending on mode, etc. there can be a mandatory wait for autoexposure, etc. Edit: I meant to say "a default setting" as you've changed some. 根据模式等,可能会强制等待自动曝光等。编辑:我打算说“默认设置”,因为你已经改变了一些。 There are also rules not codified in the driver. 还有一些规则没有在驱动程序中编纂。

The pixelformat matters. 像素格式很重要。 I encountered the similar low-fps problem, and I spent some time testing using my program in Go and C++ using V4L2 API. 我遇到了类似的低fps问题,我花了一些时间使用V4L2 API在Go和C ++中使用我的程序进行测试。 What I found is, Rpi Cam Module has good accelaration with H.264/MJPG pixelformat. 我发现,Rpi Cam Module与H.264 / MJPG pixelformat具有良好的相关性。 I can easily get 60fps at 640*480, same as non-compressed formats like YUYV/RGB. 我可以轻松获得640 * 480的60fps,与YUYV / RGB等非压缩格式相同。 However JPEG runs very slow. 但是JPEG运行速度很慢。 I can only get 4fps even at 320*240. 我只能在320 * 240时获得4fps。 And I also found the current is higher (>700mA) with JPEG compare to 500mA with H.264/MJPG. 我还发现JPEG的电流更高(> 700mA),而H.264 / MJPG的电流则高于500mA。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM