用于Linux的视频两次轮询使用errno EINVAL返回POLLERR

时间:2016-04-14 14:35:09

标签: c linux v4l2

我写了一个简单的C共享对象库,它调用v4l2(Video for Linux two)API,例如v4l2_open()。然后我试图在返回的设备句柄上轮询()但它总是在revents中返回POLLERR。我尝试了超时的不同参数,但没有帮助。这是完整的代码。

/*
 * 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;
}

有谁能告诉我代码中发生了什么?

1 个答案:

答案 0 :(得分:0)

我测试了你的代码,在我的系统上,poll调用返回0.从手册页中,&#34;值为0表示调用超时且没有文件描述符准备就绪。 #34;因此除了-1和1之外,你应该测试0。

我不知道为什么它会revents填充POLLERR,但如果revents返回1,我只会检查生成的poll字段。

此外,并非所有V4L2设备都支持read(),因此您应该通过测试caps.capabilities & V4L2_CAP_READWRITE来检查您的设备是否支持它。我测试过的笔记本电脑摄像头不支持读/写。

请参阅this example program以供参考。