[英]Setting Frame Rate on Logitech C210 webcam in C++ on Raspberry pi using v4l2
[英]Capturing YUYV in c++ using v4l2
我有一个通过 USB 连接到 beaglebone 的网络摄像头。 我正在用 C++ 编码,我的目标是从网络摄像头捕获原始的未压缩图片。 首先,我通过命令v4l2-ctl --list-formats
检查了支持哪些格式,结果是:
Index : 0
Type : Video Capture
Pixel Format: 'MJPG' (compressed)
Name : Motion-JPEG
Index : 1
Type : Video Capture
Pixel Format: 'YUYV'
Name : YUYV 4:2:2
因此,我认为如果我尝试使用 YUYV 格式,则必须有可能获得未压缩的图片。
知道这一点后,我开始用 C++ 编写程序。 我成功编写了一个程序来捕获压缩图片,但是当尝试使用格式 YUYV 捕获时它不起作用,我真的需要一些帮助来完成这项工作。
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <libv4l2.h>
template <typename typeXX>
void clear_memmory(typeXX* x) {
memset(x, 0, sizeof(*x));
}
void xioctl(int cd, int request, void *arg){
int response;
do{
//ensures we get the correct response.
response = v4l2_ioctl(cd, request, arg);
}
while (response == -1 && ((errno == EINTR) || (errno == EAGAIN)));
if (response == -1) {
fprintf(stderr, "error %d, %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
}
struct LMSBBB_buffer{
void* start;
size_t length;
};
int main(){
const char* dev_name = "/dev/video0";
int width=1920;
int height=1080;
int fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
struct v4l2_format format = {0};
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.width = width;
format.fmt.pix.height = height;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;//V4L2_PIX_FMT_YUYV //V4L2_PIX_FMT_RGB24
format.fmt.pix.field = V4L2_FIELD_NONE; //V4L2_FIELD_NONE
xioctl(fd, VIDIOC_S_FMT, &format);
printf("Device initialized.\n");
///request buffers
struct v4l2_requestbuffers req = {0};
req.count = 2;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
xioctl(fd, VIDIOC_REQBUFS, &req);
printf("Buffers requested.\n");
///mapping buffers
struct v4l2_buffer buf;
LMSBBB_buffer* buffers;
unsigned int i;
buffers = (LMSBBB_buffer*) calloc(req.count, sizeof(*buffers));
for (i = 0; i < req.count; i++) {
clear_memmory(&(buf));
(buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
(buf).memory = V4L2_MEMORY_MMAP;
(buf).index = i;
xioctl(fd, VIDIOC_QUERYBUF, &buf);
buffers[i].length = (buf).length;
printf("A buff has a len of: %i\n",buffers[i].length);
buffers[i].start = v4l2_mmap(NULL, (buf).length, PROT_READ | PROT_WRITE, MAP_SHARED,fd, (buf).m.offset);
if (MAP_FAILED == buffers[i].start) {
perror("Can not map the buffers.");
exit(EXIT_FAILURE);
}
}
printf("Buffers mapped.\n");
for (i = 0; i < req.count; i++) {
clear_memmory(&(buf));
(buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
(buf).memory = V4L2_MEMORY_MMAP;
(buf).index = i;
ioctl(fd,VIDIOC_QBUF, &(buf));
}
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd,VIDIOC_STREAMON, &type);
printf("buffers queued and streaming.\n");
int pic_count=0;
///CAPTURE
fd_set fds;
struct timeval tv;
int r;
char out_name[256];
FILE* fout;
do {
FD_ZERO(&fds);
FD_SET(fd, &fds);
// Timeout.
tv.tv_sec = 2;
tv.tv_usec = 0;
r = select(fd + 1, &fds, NULL, NULL, &tv);
} while ((r == -1 && (errno = EINTR)));
if (r == -1) {
perror("select");
exit(EXIT_FAILURE);
}
clear_memmory(&(buf));
(buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
(buf).memory = V4L2_MEMORY_MMAP;
xioctl(fd,VIDIOC_DQBUF, &(buf));
printf("Buff index: %i\n",(buf).index);
sprintf(out_name, "image%03d.ppm",pic_count);
fout = fopen(out_name, "w");
if (!fout) {
perror("Cannot open image");
exit(EXIT_FAILURE);
}
fprintf(fout, "P6\n%d %d 255\n",width, height);
fwrite(buffers[(buf).index].start, (buf).bytesused, 1, fout);
fclose(fout);
pic_count++;
clear_memmory(&(buf));
(buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
(buf).memory = V4L2_MEMORY_MMAP;
xioctl(fd,VIDIOC_DQBUF, &(buf));
printf("Buff index: %i\n",(buf).index);
sprintf(out_name, "image%03d.ppm",pic_count);
fout = fopen(out_name, "w");
if (!fout) {
perror("Cannot open image");
exit(EXIT_FAILURE);
}
fprintf(fout, "P6\n%d %d 255\n",width, height);
fwrite(buffers[(buf).index].start, (buf).bytesused, 1, fout);
fclose(fout);
pic_count++;
///xioctl(fd,VIDIOC_QBUF, &(buf));
return 0;
}
在第 50 行,我可以选择 V4L2_PIX_FMT_YUYV 和 V4L2_PIX_FMT_RGB24 之间的格式。 对于 V4L2_PIX_FMT_RGB24 我得到了图片,但是当使用 V4L2_PIX_FMT_YUYV 时我得到这个错误:
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable
libv4l2: error dequeuing buf: Resource temporarily unavailable
错误行一直存在,直到我手动结束程序。
有谁知道该怎么做? 我在这上面花了 2 个多星期,我不能从这里搬到任何地方。 我真的很感激任何建议。
据我所知,您正在从相机请求 YUYV 格式的 FullHD (1920x1080) 缓冲区。 你没有提到相机类型/型号/规格,但如果它是一个通用的 USB 连接硬件,你很可能不会得到一个原始的 FullHD YUYV 缓冲区作为输出,只有 MJPEG 一个(你可以解码为 YUV,如果您可以使用 libjpeg 进行修改)或未映射的解码 RGB 缓冲区(这几乎是带有 YUV->RGB 转换的解码 MJPEG)。
此命令可以请求具有帧速率的确切格式列表,这可能会告诉您它不提供 1920x1080 YUYV,仅提供较小的内容,例如 640x480:
v4l2-ctl --list-formats
如果您需要对原始 YUYV 相机帧进行“真正”零拷贝访问的视频处理,则首先需要直接访问硬件和特定硬件。 一旦你的软件和相机之间有了 USB 接口,你就会得到一个额外的间接访问,这意味着速度会下降。 想一想,1920x1080 的 YUYV 帧占用大约 4 兆字节的内存。 在 30 FPS 时,这是每秒 120 兆字节(或 960 兆位)的总线吞吐量。 如果您有 USB2.0 相机,则没有带宽支持(因此需要 MJPEG)。 即使在 15FPS 时,这也是 480 兆位,不包括 USB 延迟和协议开销。
为了提供一些“可操作的反馈”,我建议首先专注于要应用于图像的算法(可能,您只是不想在第一步失去处理速度)。 不要犹豫,使用 OpenCV 进行相机输入和基本图像处理,稍后您可以切换到一些硬件接口和手写算法。
获取原始帧的更简单方法是使用 Android 的相机界面,并尝试使用 GL_TEXTURE_EXTERNAL_OES 扩展使用 GLSL 着色器处理传入帧,有关该扩展的信息和代码示例可用。 在那里您可以将 GL 纹理连接到 AHardwareBuffer 实例,然后使用 AHardwareBuffer_lock 函数来获取原始指针。 确切支持的格式也可能因硬件而异,因此不要指望这非常容易。
我最近遇到了类似的问题。 在我的例子中,相机驱动程序需要 VIDIOC_S_PARM ioctl 来设置帧速率并为选定的捕获模式初始化相机。
您可以尝试在 VIDIOC_S_FMT 之后添加此代码,看看它是否也适用于您:
struct v4l2_streamparm streamparam;
memset(&streamparam, 0, sizeof(streamparam));
streamparam.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
xioctl(fd, VIDIOC_G_PARM, &streamparam);
streamparam.parm.capture.timeperframe.numerator = 1;
streamparam.parm.capture.timeperframe.denominator = 5;
xioctl(fd, VIDIOC_S_PARM, &streamparam);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.