繁体   English   中英

如何在不使用 opencv 的情况下直接在 c/c++ 中从 USB 网络摄像头读取 h264 stream 作为文件?

[英]How to read h264 stream as a file from the USB webcam directly in c/c++ without using opencv?

我能够读取 h264 格式的视频文件并在其上进行一些机器学习推理。 该代码非常适合从文件输入。 下面的代码是来自Deepstream SDK的示例代码

FileDataProvider(const char *szFilePath, simplelogger::Logger *logger)
    : logger_(logger)
    {
         fp_ = fopen(szFilePath, "rb");

        //fp_ = fopen("/dev/video0", "rb");


        if (nullptr == fp_) {
            LOG_ERROR(logger, "Failed to open file " << szFilePath);
            exit(1);
        }
        pLoadBuf_ = new uint8_t[nLoadBuf_];
        pPktBuf_ = new uint8_t[nPktBuf_];
        assert(nullptr != pLoadBuf_);
    }
    ~FileDataProvider() {
        if (fp_) {
            fclose(fp_);
        }
        if (pLoadBuf_) {
            delete [] pLoadBuf_;
        }
        if (pPktBuf_) {
            delete [] pPktBuf_;
        }
    }

什么是要求?

  • 从 Logitech c920 网络摄像头读取视频文件。
  • 我知道如何使用 opencv 从网络摄像头读取。但我不想在这里使用 opencv。

我的研究

  • 使用 v4l 我们可以获得 stream 并将其显示在 vlc 中。
  • 相机支持以下格式。

@ubox:~$ v4l2-ctl --device=/dev/video1 --list-formats

ioctl:VIDIOC_ENUM_FMT 索引:0 类型:视频捕获像素格式:'YUYV' 名称:YUYV 4:2:2

索引:1 类型:视频捕捉像素格式:“H264”(压缩)名称:H.264

索引:2 类型:视频捕获像素格式:“MJPG”(压缩)名称:Motion-JPEG

这该怎么做? - 现在如何将这个实时 stream 提供给上面的示例代码,以便它从网络摄像头而不是文件中读取?

[update-1] - 换句话说,v4l 是否有一些选项可以将视频 stream 编写为 h264 共振峰? 这样,当它(v4l)写入磁盘时,我可以像以前(上面的代码)一样读取该文件。

[update-2] - 我们可以使用ffmpeg而不是 v4l。 是否有使用 ffmpeg 将视频 stream 连续保存到磁盘的解决方案,以便其他程序读取该文件?

在使用 ioctl 从相机捕获帧之前,您需要先设置如下格式。

fp_ = open("/dev/video0", O_RDWR);
struct v4l2_format fmt = {0};
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
ioctl(fp_, VIDIOC_S_FMT, &fmt);

然后,初始化和 map 缓冲区

struct Buffer
{
    void *start;
    unsigned int length;
    unsigned int flags;
};

int buffer_count_ = 4;
Buffer *buffers_;

bool AllocateBuffer()
{
    struct v4l2_requestbuffers req = {0};
    req.count = buffer_count_;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;

    if (ioctl(fp_, VIDIOC_REQBUFS, &req) < 0)
    {
        perror("ioctl Requesting Buffer");
        return false;
    }

    buffers_ = new Buffer[buffer_count_];

    for (int i = 0; i < buffer_count_; i++)
    {
        struct v4l2_buffer buf = {0};
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        buf.index = i;
        if (ioctl(fp_, VIDIOC_QUERYBUF, &buf) < 0)
        {
            perror("ioctl Querying Buffer");
            return false;
        }

        buffers_[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, buf.m.offset);
        buffers_[i].length = buf.length;

        if (MAP_FAILED == buffers_[i].start)
        {
            printf("MAP FAILED: %d\n", i);
            for (int j = 0; j < i; j++)
                munmap(buffers_[j].start, buffers_[j].length);
            return false;
        }

        if (ioctl(fp_, VIDIOC_QBUF, &buf) < 0)
        {
            perror("ioctl Queue Buffer");
            return false;
        }
    }

    return true;
}

STREAMON 开始捕获

v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fp_, VIDIOC_STREAMON, &type);

最后从映射缓冲区中读取一帧。 通常, CaptureImage()会在 while 循环中。

Buffer CaptureImage()
{
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(fd_, &fds);
    struct timeval tv = {0};
    tv.tv_sec = 1;
    tv.tv_usec = 0;
    int r = select(fd_ + 1, &fds, NULL, NULL, &tv);
    if (r == 0)
    {
        // timeout
    }

    struct v4l2_buffer buf = {0};
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;

    while (ioctl(fp_, VIDIOC_DQBUF, &buf) < 0)
    {
        perror("Retrieving Frame");
    }

    struct Buffer buffer = {.start = buffers_[buf.index].start,
                            .length = buf.bytesused,
                            .flags = buf.flags};

    if (ioctl(fp_, VIDIOC_QBUF, &buf) < 0)
    {
        perror("Queue buffer");
    }

    return buffer;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM