c - v4l2 简单应用——性能问题
问题描述
我有一个非常简单的设置,连接到 Pi Zero 的相机由外部信号触发。
问题:我的代码使用 v4l2 可实现的帧速率 <0.4fps。适用于例如:raspivid。
使用 raspivid 1920x1080 @ 50fps 可以按预期工作(使用 -pts 测试以保存时间码)。相反,我的代码永远不会使 50Hz 的缓冲区出队。在每 ~600ms 接收帧之前,我必须将触发率降低到 5Hz!这看起来我仍然只接收每三帧。返回的帧缓冲区总是跳过一个索引:
new frame 0: 3110400
time diff 0.6006
new frame 2: 3110400
time diff 0.6006
new frame 4: 3110400
time diff 0.600601
new frame 6: 3110400
time diff 0.6006
您可以在下面找到我的代码(曝光设置,...已删除)
问题:你能告诉我可能是什么问题吗?该程序只对缓冲区进行出队和入队,因此性能不应该成为问题。
#define NB_BUFFER 10
int main(int argc, char *argv[])
{
int exposure = 50;
int rows = 1080;
int cols = 1920;
if(argc > 1){
exposure= atoi(argv[1]);
}
if(argc > 3){
cols=atoi(argv[2]);
rows=atoi(argv[3]);
}
struct vdIn vdin;
struct vdIn *vd = &vdin;
if((vd->fd = open("/dev/video0", O_RDWR)) < 0){
perror("open");
exit(1);
}
if(ioctl(vd->fd, VIDIOC_QUERYCAP, &vd->cap) < 0){
perror("VIDIOC_QUERYCAP");
exit(1);
}
if(!(vd->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)){
fprintf(stderr, "The device does not handle single-planar video capture.\n");
exit(1);
}
vd->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vd->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;//V4L2_PIX_FMT_BGR24;
vd->fmt.fmt.pix.width = cols;
vd->fmt.fmt.pix.height = rows;
if(ioctl(vd->fd, VIDIOC_S_FMT, &vd->fmt) < 0){
perror("VIDIOC_S_FMT");
exit(1);
}
struct v4l2_control control;
control.id = V4L2_CID_EXPOSURE_AUTO ;
control.value = V4L2_EXPOSURE_MANUAL;
if(ioctl(vd->fd, VIDIOC_S_CTRL, &control) < 0){
perror("VIDIOC_S_CTRL EXPOSURE MANUAL");
exit(1);
}
.... iso manual, line frequency off, set exposure, auto whitebalance off
vd->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vd->rb.memory = V4L2_MEMORY_MMAP;
vd->rb.count = NB_BUFFER;
if(ioctl(vd->fd, VIDIOC_REQBUFS, &vd->rb) < 0){
perror("VIDIOC_REQBUFS");
exit(1);
}
int ret;
/* map the buffers */
struct v4l2_buffer buf;
for (int i = 0; i < NB_BUFFER; i++) {
memset (&vd->buf, 0, sizeof (struct v4l2_buffer));
vd->buf.index = i;
vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vd->buf.memory = V4L2_MEMORY_MMAP;
ret = ioctl (vd->fd, VIDIOC_QUERYBUF, &vd->buf);
if (ret < 0) {
fprintf (stderr, "Unable to query buffer (%d).\n", errno);
return -1;
}
std::cout << "buf len " << vd->buf.length<<std::endl;
vd->mem[i] = mmap (0 /* start anywhere */ ,
vd->buf.length, PROT_READ, MAP_SHARED, vd->fd,
vd->buf.m.offset);
if (vd->mem[i] == MAP_FAILED) {
fprintf (stderr, "Unable to map buffer (%d)\n", errno);
return -1;
}
}
/* Queue the buffers. */
for (int i = 0; i < NB_BUFFER; ++i) {
memset (&vd->buf, 0, sizeof (struct v4l2_buffer));
vd->buf.index = i;
vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vd->buf.memory = V4L2_MEMORY_MMAP;
ret = ioctl (vd->fd, VIDIOC_QBUF, &vd->buf);
if (ret < 0) {
fprintf (stderr, "Unable to queue buffer (%d).\n", errno);
return -1;
}
}
// Activate streaming
int type = vd->fmt.type;
if(ioctl(vd->fd, VIDIOC_STREAMON, &type) < 0){
perror("VIDIOC_STREAMON");
exit(1);
}
bool capture_is_running = true;
double lastTimestamp=0;
while(capture_is_running){
memset (&vd->buf, 0, sizeof (struct v4l2_buffer));
vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vd->buf.memory = V4L2_MEMORY_MMAP;
std::cout << "try to dequeue" << std::endl;
ret = ioctl (vd->fd, VIDIOC_DQBUF, &vd->buf);
if (ret < 0) {
fprintf (stderr, "Unable to dequeue buffer (%d).\n", errno);
return -1;
}
cout << "new frame "<<vd->buf.index<<": "<< vd->buf.bytesused << endl;
double timestamp = vd->buf.timestamp.tv_sec + vd->buf.timestamp.tv_usec/1000000.;
double timeDiff = timestamp - lastTimestamp;
lastTimestamp = timestamp;
std::cout << "time diff " << timeDiff << std::endl;
ret = ioctl (vd->fd, VIDIOC_QBUF, &vd->buf);
if (ret < 0) {
fprintf (stderr, "Unable to requeue buffer (%d).\n", errno);
return -1;
}
}
// Deactivate streaming
if(ioctl(vd->fd, VIDIOC_STREAMOFF, &type) < 0){
perror("VIDIOC_STREAMOFF");
exit(1);
}
close(vd->fd);
return EXIT_SUCCESS;
return 0;
}
解决方案
推荐阅读
- flutter-layout - 在颤振列表视图中需要帮助
- mysql - mysql/mariadb,通过尝试插入新行并检查错误来检查行是否存在是一个坏主意吗?
- mysql - SQL:GROUP BY 并为每个组获取前两个最大的 COUNT
- python-3.x - 我的命令不能使用`async def set` | 不和谐.py
- aws-lambda - Lambda 日志显示在带有搜索选项的应用程序界面中
- asp.net - 如何调试在远程非专用 Windows 服务器上运行的 ASP.NET Web API 应用程序
- mysql - 第 1 行的错误 1052 (23000):字段列表中的列“id”不明确
- internal-server-error - responsivefilemanager 9.1 内部服务器错误
- python-3.x - 将元素添加到列表中的列中的行
- css - 通过模板文件为wordpress加载css/js?