umlaeute / v4l2loopback

v4l2-loopback device
GNU General Public License v2.0
3.72k stars 530 forks source link

select() not working #56

Open TheFrog4u opened 10 years ago

TheFrog4u commented 10 years ago

Hi, v4l2loopback works very well for me with one execption: the select() functionality (http://linuxtv.org/downloads/v4l-dvb-apis/func-select.html) which should wait for a buffer to be filled always returns 1. An example how I use it can be found here: http://linuxtv.org/downloads/v4l-dvb-apis/capture-example.html With my "real" camera select() waits for the image, but not with the v4l2loopback device, no matter if I even have a gstreamer v4l2sink coupled or not.

TheFrog4u commented 10 years ago

Just wanted to note that this topic is still hot for me. Is there a way or even a chance to fix this issue or maybe a reason why select() is not working correctly with v4l2loopback?

umlaeute commented 10 years ago

it would be great if you could provide a simple test program that exhibits the problem (ideally one that can be run in an automated test-suite)

TheFrog4u commented 10 years ago

How can I attach source code? You can basicly use the example above with simple modifications:

define OK 0

define ERR_IMAGE_ERROR -1

define ERR_IMAGE_AGAIN -2

static int read_frame(void) { struct v4l2_buffer buf; int err;

    CLEAR(buf);

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

    err = xioctl(fd, VIDIOC_DQBUF, &buf);
    if (err == -1) {
        if (errno == EAGAIN) {
            return ERR_IMAGE_AGAIN;
        } else {
            perror("VIDIOC_QBUF");
            return ERR_IMAGE_ERROR;
        }
    }

    assert(buf.index < n_buffers);

    process_image(buffers[buf.index].start, buf.bytesused, buf.index);

    err = xioctl(fd, VIDIOC_QBUF, &buf);
    if (err == -1) {
        perror("VIDIOC_QBUF");
        return ERR_IMAGE_ERROR;
    }

    return OK;

}

static void main_loop(void) { unsigned int count = READ_NUM_IMAGES; int err;

while (count-- > 0) {
    for(;;) {
        fd_set fds;
        struct timeval tv;

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

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

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

        if (err == -1) {
            if (errno == EINTR) {
                continue;
            }
            errno_exit("select");
        }

        if (err == 0) {
            fprintf(stderr, "select timeout\n");
            exit(EXIT_FAILURE);
        }

        err = read_frame();
        if (err == OK) {
            break;
        }else if (err ==  ERR_IMAGE_AGAIN) {
            fprintf(stderr, "Error capture image, retrying...\n");
            usleep(10000);  // wait 10 ms and try again..
            continue;
        } else {
            errno_exit("ERR_IMAGE_ERROR");
        }
    }
}

}

I just feed the v4l2loopback device:

gst-launch -q multifilesrc location=image01.png num_buffers=100 caps="image/png,framerate=10/1" ! pngdec ! videorate ! ffmpegcolorspace ! "video/x-raw-gray,format=(fourcc)GRAY" ! v4l2sink device=/dev/video0

and than run the example, I get:

./v4l2example Error capture image, retrying... Error capture image, retrying... Error capture image, retrying... Error capture image, retrying... Error capture image, retrying... Error capture image, retrying... Error capture image, retrying...

With an actual camera I do not get the "Error capture image, retrying..." errors which are triggered because select() always return 1, no matter if an image is actually in the buffer.

Best regards, Jens

umlaeute commented 10 years ago

i think the proper way to attach source code is by using gist...

EngineerScotty commented 1 year ago

Can verify this defect and think I see the issue:

Problem occurs when device is accessed with read() or write() rather than streaming interface. The opener->type field is only set in vidioc_streamon and vidioc_streamoff functions, and if it is not set to either READER or WRITER then v4l2_loopback_poll() always returns 0, indicating no activity on the device. Since the streaming ioctls should not be used by applications that just use read() and write(), this field is never set.

stephematician commented 1 year ago

I'm seeing the same behaviour with read/wrte using v4l2py with a loopback device; and stream_on/stream_off doesn't make a difference there - but I'm trying to drill down a bit further into the module to see if there's some flag that isn't being set correctly.

stephematician commented 1 year ago

I'm fairly sure that v4l2loopback doesn't implement a true poll/wait for V4L2_BUF_TYPE_VIDEO_OUTPUT. The poll function looks like it always falls through immediately with the POLLOUT event mask.

Looks to my eye that videoc_qbuf immediately wakes up any read (event) subscribers, too (regardless of frame rate)... so; I guess the frame rate is entirely controlled by the application.

stephematician commented 9 hours ago

Coming back to this after spending a lot more time on thing V4L + V4L2loopback; I don't believe this is a bug. Streaming I/O hasn't been negotiated correctly in the code snippet. poll() should (and does) return an error:

When the application did not call VIDIOC_STREAMON the poll() function succeeds, but sets the POLLERR flag in the revents field.