V4L2 帧率下降
V4L2 Framerate Drops
上下文
您好!我一直在为一个机器人项目开发软件,该项目将使用视觉作为主要感官之一。我一直在围绕 Raspberry Pi 3 运行 Raspbian Jessie Lite 和内核 4.9.35-v7+ 构建系统。除了其他车载传感器外,我还计划根据摄像头记录的驾驶数据训练一些 ML 模型。为了检索视频帧,我使用 v4l2 api 和 a Minoru 3D USB webcam. The source for my project can be found at https://github.com/mrpossoms/AVC2017。
问题
这真是一个奇怪的问题。我上面描述的工作正常,除了帧速率从目标 15fps 显着下降,但只有当它看着一个超过 1 米远的物体时!我录制了一个视频 here 来展示这个问题。首先,我将手非常靠近相机,您可以在终端中看到帧速率从理想的 15fps 开始。然而,当我慢慢移开我的手时,帧率下降到 7fps 左右!
这是我的相机代码:
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <string.h>
#include <strings.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include "structs.h"
#include "cam.h"
#define CAM_FPS 5
cam_t cam_open(const char* path, cam_settings_t* cfg)
{
int fd = open(path, O_RDWR);
int res;
if(fd < 0)
{
fprintf(stderr, "Error opening video device '%s'\n", path);
//exit(-1);
cam_t empty = {};
return empty;
}
struct v4l2_capability cap;
res = ioctl(fd, VIDIOC_QUERYCAP, &cap);
if(res < 0)
{
fprintf(stderr, "Error: %d querying '%s' for capabilities (%d)\n", res, path, errno);
exit(-2);
}
if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
{
fprintf(stderr, "Error: '%s' lacks V4L2_CAP_VIDEO_CAPTURE capability\n", path);
}
res = cam_config(fd, cfg);
if(res < 0)
{
fprintf(stderr, "Error: %d configuring '%s' (%d)\n", res, path, errno);
exit(-3);
}
// Inform v4l about the buffers we want to receive data through
struct v4l2_requestbuffers bufrequest = {};
bufrequest.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufrequest.memory = V4L2_MEMORY_MMAP;
bufrequest.count = 2;
if(ioctl(fd, VIDIOC_REQBUFS, &bufrequest) < 0)
{
fprintf(stderr, "VIDIOC_REQBUFS\n");
exit(-4);
}
if(bufrequest.count < 2)
{
fprintf(stderr, "Not enough memory\n");
exit(-5);
}
struct v4l2_buffer bufferinfo = {};
void** fbs = calloc(sizeof(void*), bufrequest.count);
for(int i = bufrequest.count; i--;)
{
bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo.memory = V4L2_MEMORY_MMAP;
bufferinfo.index = i;
if(ioctl(fd, VIDIOC_QUERYBUF, &bufferinfo) < 0)
{
fprintf(stderr, "VIDIOC_QUERYBUF\n");
exit(-5);
}
fbs[i] = mmap(
NULL,
bufferinfo.length,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
bufferinfo.m.offset
);
if(fbs[i] == MAP_FAILED)
{
fprintf(stderr, "mmap failed\n");
exit(-6);
}
bzero(fbs[i], bufferinfo.length);
ioctl(fd, VIDIOC_QBUF, &bufferinfo);
}
cam_t cam = {
.fd = fd,
.frame_buffers = fbs,
.buffer_info = bufferinfo,
};
cam_wait_frame(&cam);
int type = bufferinfo.type;
if(ioctl(fd, VIDIOC_STREAMON, &type) < 0)
{
fprintf(stderr, "Error starting streaming\n");
exit(-7);
}
return cam;
}
int cam_request_frame(cam_t* cam)
{
cam->buffer_info.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
cam->buffer_info.memory = V4L2_MEMORY_MMAP;
return ioctl(cam->fd, VIDIOC_QBUF, &cam->buffer_info);
}
int cam_wait_frame(cam_t* cam)
{
ioctl(cam->fd, VIDIOC_DQBUF, &cam->buffer_info);
}
int cam_config(int fd, cam_settings_t* cfg)
{
int res = 0;
struct v4l2_format format;
if(!cfg)
{
fprintf(stderr, "Error: null configuration provided\n");
return -1;
}
/*
res = ioctl(fd, VIDIOC_G_FMT, &format);
if(res < 0)
{
fprintf(stderr, "Error: failed retrieving camera settings (%d)\n", errno);
return -2;
}
*/
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
format.fmt.pix.width = cfg->width;
format.fmt.pix.height = cfg->height;
if(ioctl(fd, VIDIOC_S_FMT, &format) < 0)
{
fprintf(stderr, "Error: failed applying camera settings\n");
return -3;
}
struct v4l2_streamparm parm = {};
parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
parm.parm.capture.timeperframe.numerator = 1;
parm.parm.capture.timeperframe.denominator = 15;
res = ioctl(fd, VIDIOC_S_PARM, &parm);
return 0;
}
我可以 100% 地重现问题,但我真的不知道是什么导致了这种行为。非常感谢任何建议或想法。
正如马克所说,问题出在曝光上。驱动程序必须决定在较暗的情况下每帧需要更多的曝光时间。只需将相机带到室外即可立即将帧速率提高到目标 15fps。
上下文
您好!我一直在为一个机器人项目开发软件,该项目将使用视觉作为主要感官之一。我一直在围绕 Raspberry Pi 3 运行 Raspbian Jessie Lite 和内核 4.9.35-v7+ 构建系统。除了其他车载传感器外,我还计划根据摄像头记录的驾驶数据训练一些 ML 模型。为了检索视频帧,我使用 v4l2 api 和 a Minoru 3D USB webcam. The source for my project can be found at https://github.com/mrpossoms/AVC2017。
问题
这真是一个奇怪的问题。我上面描述的工作正常,除了帧速率从目标 15fps 显着下降,但只有当它看着一个超过 1 米远的物体时!我录制了一个视频 here 来展示这个问题。首先,我将手非常靠近相机,您可以在终端中看到帧速率从理想的 15fps 开始。然而,当我慢慢移开我的手时,帧率下降到 7fps 左右!
这是我的相机代码:
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <string.h>
#include <strings.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include "structs.h"
#include "cam.h"
#define CAM_FPS 5
cam_t cam_open(const char* path, cam_settings_t* cfg)
{
int fd = open(path, O_RDWR);
int res;
if(fd < 0)
{
fprintf(stderr, "Error opening video device '%s'\n", path);
//exit(-1);
cam_t empty = {};
return empty;
}
struct v4l2_capability cap;
res = ioctl(fd, VIDIOC_QUERYCAP, &cap);
if(res < 0)
{
fprintf(stderr, "Error: %d querying '%s' for capabilities (%d)\n", res, path, errno);
exit(-2);
}
if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
{
fprintf(stderr, "Error: '%s' lacks V4L2_CAP_VIDEO_CAPTURE capability\n", path);
}
res = cam_config(fd, cfg);
if(res < 0)
{
fprintf(stderr, "Error: %d configuring '%s' (%d)\n", res, path, errno);
exit(-3);
}
// Inform v4l about the buffers we want to receive data through
struct v4l2_requestbuffers bufrequest = {};
bufrequest.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufrequest.memory = V4L2_MEMORY_MMAP;
bufrequest.count = 2;
if(ioctl(fd, VIDIOC_REQBUFS, &bufrequest) < 0)
{
fprintf(stderr, "VIDIOC_REQBUFS\n");
exit(-4);
}
if(bufrequest.count < 2)
{
fprintf(stderr, "Not enough memory\n");
exit(-5);
}
struct v4l2_buffer bufferinfo = {};
void** fbs = calloc(sizeof(void*), bufrequest.count);
for(int i = bufrequest.count; i--;)
{
bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bufferinfo.memory = V4L2_MEMORY_MMAP;
bufferinfo.index = i;
if(ioctl(fd, VIDIOC_QUERYBUF, &bufferinfo) < 0)
{
fprintf(stderr, "VIDIOC_QUERYBUF\n");
exit(-5);
}
fbs[i] = mmap(
NULL,
bufferinfo.length,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
bufferinfo.m.offset
);
if(fbs[i] == MAP_FAILED)
{
fprintf(stderr, "mmap failed\n");
exit(-6);
}
bzero(fbs[i], bufferinfo.length);
ioctl(fd, VIDIOC_QBUF, &bufferinfo);
}
cam_t cam = {
.fd = fd,
.frame_buffers = fbs,
.buffer_info = bufferinfo,
};
cam_wait_frame(&cam);
int type = bufferinfo.type;
if(ioctl(fd, VIDIOC_STREAMON, &type) < 0)
{
fprintf(stderr, "Error starting streaming\n");
exit(-7);
}
return cam;
}
int cam_request_frame(cam_t* cam)
{
cam->buffer_info.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
cam->buffer_info.memory = V4L2_MEMORY_MMAP;
return ioctl(cam->fd, VIDIOC_QBUF, &cam->buffer_info);
}
int cam_wait_frame(cam_t* cam)
{
ioctl(cam->fd, VIDIOC_DQBUF, &cam->buffer_info);
}
int cam_config(int fd, cam_settings_t* cfg)
{
int res = 0;
struct v4l2_format format;
if(!cfg)
{
fprintf(stderr, "Error: null configuration provided\n");
return -1;
}
/*
res = ioctl(fd, VIDIOC_G_FMT, &format);
if(res < 0)
{
fprintf(stderr, "Error: failed retrieving camera settings (%d)\n", errno);
return -2;
}
*/
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
format.fmt.pix.width = cfg->width;
format.fmt.pix.height = cfg->height;
if(ioctl(fd, VIDIOC_S_FMT, &format) < 0)
{
fprintf(stderr, "Error: failed applying camera settings\n");
return -3;
}
struct v4l2_streamparm parm = {};
parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
parm.parm.capture.timeperframe.numerator = 1;
parm.parm.capture.timeperframe.denominator = 15;
res = ioctl(fd, VIDIOC_S_PARM, &parm);
return 0;
}
我可以 100% 地重现问题,但我真的不知道是什么导致了这种行为。非常感谢任何建议或想法。
正如马克所说,问题出在曝光上。驱动程序必须决定在较暗的情况下每帧需要更多的曝光时间。只需将相机带到室外即可立即将帧速率提高到目标 15fps。