首页 > 解决方案 > v4l2 设备需要在应用重启时重新插入

问题描述

我有一个简单的 c++ 程序,其中类似以下代码的代码在线程中运行以获取恒定的网络摄像头提要。第一次一切都按预期工作。但是在关闭应用程序并再次运行后。select() 函数超时,我从来没有从相机中得到一帧。虽然 LED 应该亮起。该相机无需重新插入任何其他 wecam 应用程序即可使用。看起来我的代码没有正确重置或关闭?

fd = v4l2_open("/dev/video0", O_RDWR | O_NONBLOCK, 0);

// check if device is ready
v4l2_capability capability{};
ioctl(fd, VIDIOC_QUERYCAP, &capability);

// set Image format
v4l2_format imageFormat;
imageFormat.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
imageFormat.fmt.pix.width = s.width;
imageFormat.fmt.pix.height = s.height;
imageFormat.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
imageFormat.fmt.pix.field = V4L2_FIELD_NONE;
// tell the device you are using this format
ioctl(fd, VIDIOC_S_FMT, &imageFormat);

v4l2_requestbuffers req{};
req.count = buffers.size();
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;

xioctl(fd, VIDIOC_REQBUFS, &req);

for (unsigned i = 0; i < req.count; i++) {
    // query buffer
    v4l2_buffer buf{};
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = i;
    xioctl(fd, VIDIOC_QUERYBUF, &buf);

    // map data to buffer
    auto b = v4l2_mmap(nullptr, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
    buffers[i].start = reinterpret_cast<uint8_t *>(b);
    buffers[i].length = buf.length;
}

for (unsigned i = 0; i < req.count; i++) {
    v4l2_buffer buf{};
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = i;
    xioctl(fd, VIDIOC_QBUF, &buf);
}

auto type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
xioctl(fd, VIDIOC_STREAMON, &type);

while (bKeepRunning) {
    fd_set fds;
    timeval tv{};
    int r;

    FD_ZERO(&fds);
    FD_SET(fd, &fds);

    /* Timeout. */
    tv.tv_sec = 1;
    tv.tv_usec = 0;

    r = select(fd + 1, &fds, NULL, NULL, &tv);

    if (r <= 0) {
        continue;
    }

    v4l2_buffer buf{};

    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;

    // retreive buffer
    if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
        continue;
    }

    int jpegSubsamp, jpegW, jpegH;
    auto start = buffers[buf.index].start;
    auto data = jpgd::decompress_jpeg_image_from_memory(start, buf.bytesused, &jpegW, &jpegH, &jpegSubsamp, 3);

    // release buffer
    xioctl(fd, VIDIOC_QBUF, &buf);
}

xioctl(fd, VIDIOC_STREAMOFF, &type);

for (auto &buffer: buffers) {
    if (buffer.length == 0) continue;
    v4l2_munmap(buffer.start, buffer.length);
}
v4l2_close(fd);

标签: c++linuxv4l2

解决方案


推荐阅读