简体   繁体   中英

Video for Linux two poll returning POLLERR with errno EINVAL

I'v written a simple C shared object library which calls v4l2(Video for Linux two) API eg v4l2_open(). Then I'm trying to poll() on the returned device handle but it always return POLLERR in the revents. I tried different parameters with timeout but it does not help. Here is the complete code.

/*
 * libwebcam.h
 *
 *  Created on: 13.04.2016
 *      Author: max
 */

#ifndef LIBWEBCAM_H_
#define LIBWEBCAM_H_

#include <stdint.h>

struct webcam
{
    int fd;
    uint32_t width;
    uint32_t height;
    uint32_t sizeimage;
    uint32_t bytesperline;
    uint8_t *image_buffer;
    void *priv_data;
};

int webcam_open(struct webcam *w);
int webcam_close(struct webcam *w);
int webcam_take_image(struct webcam *w);
int webcam_poll(struct webcam *w);

#endif /* LIBWEBCAM_H_ */

/*
 * libwebcam.c
 *
 *  Created on: 13.04.2016
 *      Author: max
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <libv4l2.h>
#include <poll.h>
#include "libwebcam.h"

int webcam_open(struct webcam *w)
{
    struct v4l2_capability caps;
    struct v4l2_format fmt;
    int dev_index;
    int dev;
    char buffer[255];

    for (dev_index = 0; dev_index < 64; dev_index++) {
        memset(&buffer, 0, sizeof(buffer));
        sprintf(buffer, "/dev/video%d", dev_index);
#ifdef DEBUG
        printf("libwebcam: Probing %s\n", buffer);
#endif
        dev = v4l2_open(buffer, O_RDWR | O_NONBLOCK, 0);
        if (dev != -1) {
            memset(&caps, 0, sizeof(caps));
            if (v4l2_ioctl(dev, VIDIOC_QUERYCAP, &caps) == -1) {
                return -1;
            }
            if (caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
#ifdef DEBUG
                printf("libwebcam: %s is video capture device\n", buffer);
#endif
                memset(&fmt, 0, sizeof(fmt));
                fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                if(v4l2_ioctl(dev, VIDIOC_G_FMT, &fmt) == -1) {
                    return -1;
                }
                fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
                if(v4l2_ioctl(dev, VIDIOC_S_FMT, &fmt) == -1) {
                    return -1;
                }
                if(v4l2_ioctl(dev, VIDIOC_G_FMT, &fmt) == -1) {
                    return -1;
                }
                if(w)
                {
                    w->fd = dev;
                    w->bytesperline = fmt.fmt.pix.bytesperline;
                    w->height = fmt.fmt.pix.height;
                    w->sizeimage = fmt.fmt.pix.sizeimage;
                    w->width = fmt.fmt.pix.width;
                    w->image_buffer = calloc(fmt.fmt.pix.sizeimage, sizeof(uint8_t));
                    if(w->image_buffer == NULL)
                        return -1;
                    w->priv_data = calloc(1, sizeof(struct pollfd));
                    if(w->priv_data == NULL)
                        return -1;
                    return 0;
                }
                else
                {
                    errno = EINVAL;
                    return -1;
                }
            }
        }
    }
    errno = ENODEV;
    return -1;
}

int webcam_close(struct webcam *w)
{
    if(w)
    {
        if(w->image_buffer != NULL){
            free(w->image_buffer);
            w->image_buffer = NULL;
        }
        if(w->priv_data != NULL) {
            free(w->priv_data);
            w->priv_data = NULL;
        }
        if(w->fd != -1)
            if(v4l2_close(w->fd) == -1)
                return -1;
        return 0;
    }
    errno = EINVAL;
    return -1;
}

int webcam_take_image(struct webcam *w)
{
    if(w)
    {
        return v4l2_read(w->fd, w->image_buffer, w->sizeimage * sizeof(uint8_t));
    }
    errno = EINVAL;
    return -1;
}

int webcam_poll(struct webcam *w)
{
    if(w)
    {
        ((struct pollfd *)w->priv_data)->events = POLLIN;
        ((struct pollfd *)w->priv_data)->revents = 0;
        ((struct pollfd *)w->priv_data)->fd = w->fd;
        if(poll(((struct pollfd*)w->priv_data), 1, -1) == -1)
        {
            return -1;
        }

        if(((struct pollfd*)w->priv_data)->revents & POLLIN) {
#ifdef DEBUG
            printf("libwebcam: Data is available...\n");
#endif
            return 1;
        }
        if(((struct pollfd*)w->priv_data)->revents & POLLERR) {
#ifdef DEBUG
            printf("libwebcam: Error in poll...\n");
#endif
            return -1;
        }

#ifdef DEBUG
        printf("libwebcam: Timeout...\n");
#endif
        return 0;
    }
#ifdef DEBUG
    printf("libwebcam: Struct not valid...\n");
#endif
    errno = EINVAL;
    return -1;
}

/*
 * test.c
 *
 *  Created on: 14.04.2016
 *      Author: max
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libwebcam.h>

int main(int argc, char **argv)
{
    struct webcam w;
    int polled;

    memset(&w, 0, sizeof(w));

    if(webcam_open(&w) == -1)
    {
        perror("Unable to find webcam");
        return EXIT_FAILURE;
    }

    while(1)
    {
        polled = webcam_poll(&w);
        if(polled == -1)
        {
            perror("Error in poll");
            return EXIT_FAILURE;
        }

        if(polled == 1)
        {
            webcam_take_image(&w);
        }
    }

    if(webcam_close(&w) == -1)
    {
        perror("Unable to close webcam");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

Can anyone tell me what is going on in the code?

I tested your code, and on my system the poll call is returning 0. From the man page, "A value of 0 indicates that the call timed out and no file descriptors were ready." So you should test for 0 in addition to -1 and 1.

I don't know why it fills in revents with POLLERR , but I would only check the resulting revents field if poll returned 1.

Also, not all V4L2 devices support read() , so you should check that your device supports it by testing caps.capabilities & V4L2_CAP_READWRITE . My laptop webcam where I tested this does not support read/write.

See this example program for reference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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