如何解决v4l2 简单应用——性能问题
我有一个非常简单的设置,其中连接到 Pi Zero 的相机由外部信号触发。
问题:我的代码使用 v4l2 时可实现的帧速率为
使用 raspivid 1920x1080 @ 50fps 可以正常工作(使用 -pts 进行测试以保存时间码)。相反,我的代码永远不会以 50Hz 的频率使缓冲区出列。在每约 600 毫秒接收帧之前,我必须将触发率降低到 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,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,VIdioC_QBUF,"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,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,"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,&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;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。