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

ltskdhd1  于 2022-11-27  发布在  C/C++
关注(0)|答案(1)|浏览(250)

我可以读取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。
  • 我的研究 *
  • 使用v4 l,我们可以得到流并在vlc中显示它。
  • 相机支持以下格式。

@ubox:~ $v4l2-ctl --设备=/dev/视频1--列表格式
索引:0类型:视频捕获像素格式:'YUYV'姓名:YUYV 4:2:2
索引:1类型:视频捕获像素格式:“H264”(压缩)名称:H.264
索引:2类型:视频捕获像素格式:'MJPG'(压缩)名称:动态JPEG

  • Reading output of a USB webcam in Linux
  • vlc v4l2:///dev/video1 --v4l2-chroma=h264-显示来自网络摄像头的视频。
  • 如何做到这一点?* -现在如何把这个直播流到上面的示例代码,使它从网络摄像头而不是文件读取?
    [update-1]-换句话说,v4 l是否有一些选项可以将视频流写为h264共振峰?这样,当它(v4 l)写入磁盘时,我可以像以前一样读取该文件(上面的代码)。
    [update-2]-我们可以使用ffmpeg代替v4 l。如果有任何解决方案可以使用ffmpeg将视频流连续保存到磁盘中,以便其他程序读取该文件?
8zzbczxx

8zzbczxx1#

在使用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);

最后从Map的缓冲区中读取一个帧。通常,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;
}

相关问题