5

作为 V4L 的新手,我决定开始使用 video4linux2 库,以便用 C 语言从我的相机中捕获一帧(我正在使用带有 Ricoh Co. 相机的 uvcvideo 模块)。我遵循了几个指南和教程,并设法获得了一个正在运行的程序。我的问题主要是关于这个通常的代码行:

struct v4l2_format format = {0};
format.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
// ...

这是我设置捕获时使用的实际视频格式的地方。如您所见,在此示例中,我使用的是 MJPEG ( http://lxr.free-electrons.com/source/include/uapi/linux/videodev2.h#L390 )。尽管这可能是一种很好的格式,但我的应用程序可能需要简单的 RGB 格式,我猜是每个像素的像素。出于这个原因,我尝试使用 RGB 格式常量,例如V4L2_PIX_FMT_RGB24. 现在由于某种原因...... v4l2 不喜欢它。我猜这与硬件有关,但我想尽可能避免 MJPEG 操作。出于测试目的,我尝试使用其他常量和格式,但无论我做什么,v4l2 都会不断更改pixelformat字段的值:

xioctl(fd, VIDIOC_S_FMT, &format); // This call succeeds with errno != EINTR.
if(format.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24){
    // My program always enters this block when not using MJPEG.
    fprintf(stderr, "Format wasn't accepted by v4l2.");
    exit(4);
}

现在我的问题是:有没有一种方法可以获得可接受的视频格式列表(我的意思是,被我的相机/v4l2 接受),我可以从中选择 MJPEG 以外的其他格式?如果您认为我必须坚持使用 MJPEG,您会向我推荐任何允许我操作它并最终在 GUI 框架中撤回捕获的库吗?

野蛮人测试代码

我使用以下技巧来测试我的硬件上的所有可用格式。首先,一些shell脚本来获取所有格式的列表......

grep 'V4L2_PIX_FMT' /usr/include/linux/videodev2.h | grep define | tr '\t' ' ' | cut -d' ' -f2 | sed 's/$/,/g'

...在此 C 程序中使用其输出:

int formats[] = {/* result of above command */};
int i = 0;
struct v4l2_format format = {0};

for(i = 0; i < /* number of lines in previous command output */; i++){
    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    format.fmt.pix.width = 320;
    format.fmt.pix.height = 240;
    format.fmt.pix.pixelformat = formats[i];
    format.fmt.pix.field = V4L2_FIELD_NONE;
    if(xioctl(fd, VIDIOC_S_FMT, &format) != -1 && format.fmt.pix.pixelformat == formats[i])
        fprintf(stderr, "Accepted : %d\n", i);
}

该测试表明只有V4L2_PIX_FMT_YUYV并且V4L2_PIX_FMT_MJPEG是功能性的。有什么办法可以改善这一点,还是与硬件有关?

4

2 回答 2

10

在 Linux 中,命令行实用程序v4l2-ctl显示所有网络摄像头本机支持的格式 - 使用 安装它,使用 其中的摄像头索引sudo apt-get install v4l-utils运行它,如. 这些格式通过模块报告给内核模块,并由网络摄像头芯片组原生支持。仅支持列出的格式,其他任何内容都需要用户编码,并且很少提供 RGB,尽管几乎所有 CCD 都在 Bayer RGGB 中工作。到目前为止,最常见的格式是 YUV422(YUYV 或YUY2)和 MJPEG,它们有一定的重叠:MJPEG 为大分辨率实现了更大的帧速率。v4l2-ctl -dX --list-formats-extX/dev/videoXv4l2uvcvideov4l2

用于列出相机格式的 C++ 代码可以在此处的 Linux 的 Chromium GetDeviceSupportedFormats() 实现中找到。

如果您必须插入代码将 YUV 转换为 RGB,我推荐libyuv,它已针对大量架构进行了优化。

于 2014-03-23T20:11:37.850 回答
3

为了枚举可用的格式,您可以使用 ioctl VIDIOC_ENUM_FMT

要打印您支持的捕获格式的描述,/dev/video0可以这样处理:

#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/videodev2.h>

int main()
{
    int fd = v4l2_open("/dev/video0", O_RDWR);
    if (fd != -1)
    {
        struct v4l2_fmtdesc fmtdesc;
        memset(&fmtdesc,0,sizeof(fmtdesc));
        fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        while (ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc) == 0)
        {    
            printf("%s\n", fmtdesc.description);
            fmtdesc.index++;
        }
        v4l2_close(fd);
    }
}
于 2015-12-06T13:24:01.617 回答