2

I have a simple c++ program where something like the following code is running in a thread to get a constant webcam feed. The first time everything works as expected. But after closing the application and running it again. The select() function times out and I never get a frame from the camera. Though the LED lights up as it should. The camera is usable without replugging within any other wecam application. It looks like my code is not properly resetting or shutting down?

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);
underdoeg
  • 1,862
  • 4
  • 14
  • 26
  • Looks like the issue might be part of my camera. I just tried another one and the code seems to work ok – underdoeg May 05 '19 at 21:27
  • I've had similar problems using Logitech cameras with a raspberry PI. There is a way to reset the device, that works for me: https://askubuntu.com/a/61165/140035 – jamieguinan May 06 '19 at 21:22
  • thanks. yes, it looks like it is logitech device specific. I tried the same code with a newer brio and it all works fine... – underdoeg May 07 '19 at 08:16

0 Answers0