微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

VIDIOC_S_FMT 给出错误但类型正确

如何解决VIDIOC_S_FMT 给出错误但类型正确

在执行 ioctl(fd,VIdioC_S_FMT,&fmt) 时,我收到一个错误,指出 fmt 的类型错误

我正在尝试将相机与谷歌珊瑚连接起来。但是,它与电路板没有任何 I2C 连接。因此,我使用带有 v4l2 的 videodev2 API 来编写我自己的“驱动程序”。由于没有 I2C 连接,我自己填写 v4l2_format 结构,为此查看 documentation。据说 VIdioC_G_FMT 将用它拥有的信息尽可能地填充结构,并使用 VIdioC_S_FMT 使用预填充的结构。因此,我为此特定部分的代码如下所示:

CLEAR(fmt);   // set the format of the v4l2 video

        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;

        if (-1 == xioctl(fd,VIdioC_G_FMT,&fmt))
                errno_exit("VIdioC_G_FMT");

        printf("fmt.fmt.pix.width = %d\n",fmt.fmt.pix.width);
        printf("fmt.fmt.pix.pixelformat = %d\n",fmt.fmt.pix.pixelformat);

        printf("Set RGB888\r\n");
        fmt.fmt.pix.width       = 640; //replace
        fmt.fmt.pix.height      = 483; //replace
        fmt.fmt.pix.pixelformat = SDE_PIX_FMT_RGB_888; //replace
        fmt.fmt.pix.field       = V4L2_FIELD_ANY;

        printf("fmt fields adjusted\n");
        printf("fmt.type = %d\n",fmt.type);

        if (-1 == xioctl(fd,&fmt)){
                  switch (errno) {
                  case EAGAIN:
                          printf("EAGAIN\n");
                          break;

                  case EINVAL:
                          printf("EINVAL,fmt.type field is invalid\n");
                          break;

                  case EBADR:
                          printf("EBADR\n");
                          break;

                  case EBUSY:
                          printf("EBUSY\n");
                          break;

                  /* fall through */
                }
                errno_exit("VIdioC_S_FMT");
        }

我得到了错误

EINVAL,fmt.type field is invalid
VIdioC_S_FMT error 22,Invalid argument

每次,即使类型填写正确。我不知道这是怎么回事。

任何帮助将不胜感激!

完整代码

/*
 *  V4L2 video capture example
 *
 *  This program can be used and distributed without restrictions.
 *
 *      This program is provided with the V4L2 API
 * see http://linuxtv.org/docs.PHP for more information
 */

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

#include <getopt.h>             /* getopt_long() */

#include <fcntl.h>              /* low-level I/O */
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include <linux/videodev2.h>


#define CLEAR(x) memset(&(x),sizeof(x))
#define SDE_PIX_FMT_RGB_888     V4L2_PIX_FMT_RGB24 // from: https://android.googlesource.com/kernel/msm/+/android-7.1.0_r0.2/include/uapi/media/msm_sde_rotator.h

#ifndef V4L2_PIX_FMT_H264
#define V4L2_PIX_FMT_H264     v4l2_fourcc('H','2','6','4') /* H264 with start codes */
#endif

struct buffer {
        void   *start;
        size_t  length;
};

static char            *dev_name;
static int              fd = -1;
struct buffer          *buffers;
static unsigned int     n_buffers;
static int              out_buf;
static int              force_format;
static int              frame_count = 200;
static int              frame_number = 0;

static void errno_exit(const char *s)
{
        fprintf(stderr,"%s error %d,%s\n",s,errno,strerror(errno));
        exit(EXIT_FAILURE);
}

static int xioctl(int fh,int request,void *arg)
{
        int r;

        do {
                r = ioctl(fh,request,arg);
        } while (-1 == r && EINTR == errno);

        return r;
}

static void process_image(const void *p,int size)
{
        printf("processing image\n");
        frame_number++;
        char filename[15];
        sprintf(filename,"frame-%d.raw",frame_number);    // filename becomes frame-x.raw
        FILE *fp=fopen(filename,"wb");

        if (out_buf)
                fwrite(p,size,1,fp);                     // write data to file fp

        fflush(fp);
        fclose(fp);
}

static int read_frame(void)
{
        printf("reading frame\n");
        struct v4l2_buffer buf;
        unsigned int i;

        /*
        CLEAR(buf);

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

        if (-1 == xioctl(fd,VIdioC_DQBUF,&buf)) {
                switch (errno) {
                case EAGAIN:
                        return 0;

                case EIO:
                        /* Could ignore EIO,see spec.

                        /* fall through

                default:
                        errno_exit("VIdioC_DQBUF");
                }
        }

        assert(buf.index < n_buffers);

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

        if (-1 == xioctl(fd,VIdioC_QBUF,&buf))
                errno_exit("VIdioC_QBUF");

        */

        CLEAR(buf);

                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory = V4L2_MEMORY_USERPTR;

                if (-1 == xioctl(fd,&buf)) {
                        switch (errno) {
                        case EAGAIN:
                                return 0;

                        case EIO:
                                /* Could ignore EIO,see spec. */

                                /* fall through */

                        default:
                                errno_exit("VIdioC_DQBUF");
                        }
                }

                for (i = 0; i < n_buffers; ++i)
                        if (buf.m.userptr == (unsigned long)buffers[i].start
                            && buf.length == buffers[i].length)
                                break;

                assert(i < n_buffers);

                process_image((void *)buf.m.userptr,buf.bytesused);

                if (-1 == xioctl(fd,&buf))
                        errno_exit("VIdioC_QBUF");

        return 1;
}

static void mainloop(void)
{
        printf("mainloop\n");
        unsigned int count;

        count = frame_count;

        while (count-- > 0) {
                printf("count number = %d\n",count );
                for (;;) {
                        fd_set fds;
                        struct timeval tv;
                        int r;

                        FD_ZERO(&fds);      // clear file descriptor
                        FD_SET(fd,&fds);   // set file descriptors to the descriptor fd

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

                        r = select(fd + 1,&fds,NULL,&tv);    // select uses a timeout,allows program to monitor file descriptors waiting untill files becomes "ready"
                        // returns the number of file descriptors changed. This maybe zero if timeout expires.
                        // probably watching reafds descriptor to change?
                        if (-1 == r) {
                                if (EINTR == errno)
                                        continue;
                                errno_exit("select");
                        }

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

                        if (read_frame())   // if one of the descriptors is set,a frame can be read.
                                break;
                        /* EAGAIN - continue select loop. */
                }
        }
        printf("mainloop ended\n");
}

static void stop_capturing(void)
{
        printf("stop capturing\n");
        enum v4l2_buf_type type;

        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        if (-1 == xioctl(fd,VIdioC_STREAMOFF,&type))
                errno_exit("VIdioC_STREAMOFF");
        printf("capturing stopped\n");
}

static void start_capturing(void)
{
        printf("initiating capturing\n");
        unsigned int i;
        enum v4l2_buf_type type;

        /*
        for (i = 0; i < n_buffers; ++i) {
                struct v4l2_buffer buf;

                CLEAR(buf);
                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory = V4L2_MEMORY_MMAP;
                buf.index = i;

                if (-1 == xioctl(fd,&buf))
                        errno_exit("VIdioC_QBUF");
        }

        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

        if (-1 == xioctl(fd,VIdioC_STREAMON,&type)){
                errno_exit("VIdioC_STREAMON");
        }
        */

        struct v4l2_format fmt1;

        fmt1.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        ioctl(fd,&fmt1);

        printf("fmt1.fmt.pix.width = %d\n",fmt1.fmt.pix.width);
        printf("fmt1.fmt.pix.pixelformat = %d\n",fmt1.fmt.pix.pixelformat);

        for (i = 0; i < n_buffers; ++i) {
                struct v4l2_buffer buf;
                printf("%d\n",i);
                CLEAR(buf);
                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory = V4L2_MEMORY_USERPTR;
                buf.index = i;
                buf.m.userptr = (unsigned long)buffers[i].start;
                buf.length = buffers[i].length;
                printf("length %d\n",buf.length);

                if (-1 == xioctl(fd,&buf))
                        switch (errno) {
                        case EAGAIN:
                                printf("EAGAIN\n");
                                break;

                        case EINVAL:
                                printf("EINVAL\n");
                                break;

                        case EBADR:
                                printf("EBADR\n");
                                break;

                        case EBUSY:
                                printf("EBUSY\n");
                                break;

                        /* fall through */
                      }

                        errno_exit("VIdioC_QBUF");
        }

        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        if (-1 == xioctl(fd,&type))
                errno_exit("VIdioC_STREAMON");

        printf("capturing initiated\n");
}

static void uninit_device(void)
{
        unsigned int i;

        /*
        for (i = 0; i < n_buffers; ++i){
                if (-1 == munmap(buffers[i].start,buffers[i].length)){
                        errno_exit("munmap");
                }
        }
        */

        for (i = 0; i < n_buffers; ++i)
                free(buffers[i].start);

        free(buffers);
}


static void init_mmap(void)
{
        printf("initiating mmap buffer\n");
        struct v4l2_requestbuffers req;   //struct with details of the buffer to compose

        CLEAR(req);

        req.count = 2;
        req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        req.memory = V4L2_MEMORY_MMAP;

        printf("ioctl VIdioC_REQBUFS\n");
        if (-1 == xioctl(fd,VIdioC_REQBUFS,&req)) { // initiate buffer
                if (EINVAL == errno) {
                        printf("EINVAL\n");
                        fprintf(stderr,"%s does not support "
                                 "memory mapping\n",dev_name);
                        exit(EXIT_FAILURE);
                } else {
                        printf("other option\n");
                        errno_exit("VIdioC_REQBUFS");
                }
        }
        printf("memory allocated\n");

        if (req.count < 2) {
                fprintf(stderr,"Insufficient buffer memory on %s\n",dev_name);
                exit(EXIT_FAILURE);
        }

        buffers = calloc(req.count,sizeof(*buffers));    // make the amount of buffers available

        if (!buffers) {
                fprintf(stderr,"Out of memory\n");
                exit(EXIT_FAILURE);
        }

        for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {   // go through buffers and adjust struct in it
                struct v4l2_buffer buf;

                CLEAR(buf);

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

                if (-1 == xioctl(fd,VIdioC_QUERYBUF,&buf))
                        errno_exit("VIdioC_QUERYBUF");

                buffers[n_buffers].length = buf.length;
                buffers[n_buffers].start =
                        mmap(NULL /* start anywhere */,buf.length,PROT_READ | PROT_WRITE /* required */,MAP_SHARED /* recommended */,fd,buf.m.offset);

                if (MAP_Failed == buffers[n_buffers].start)
                        errno_exit("mmap");
        }
        printf("mmap buffer initiated\n");
}


static void init_userp(unsigned int buffer_size)
{
        printf("initiating userpointer\n");

        struct v4l2_requestbuffers req;

        CLEAR(req);

        req.count  = 4;
        req.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        req.memory = V4L2_MEMORY_USERPTR;

        if (-1 == xioctl(fd,&req)) {
                if (EINVAL == errno) {
                        fprintf(stderr,"%s does not support "
                                 "user pointer I/O\n",dev_name);
                        exit(EXIT_FAILURE);
                } else {
                        errno_exit("VIdioC_REQBUFS");
                }
        }

        buffers = calloc(4,sizeof(*buffers));

        if (!buffers) {
                fprintf(stderr,"Out of memory\n");
                exit(EXIT_FAILURE);
        }

        for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
                buffers[n_buffers].length = buffer_size;
                buffers[n_buffers].start = malloc(buffer_size);

                if (!buffers[n_buffers].start) {
                        fprintf(stderr,"Out of memory\n");
                        exit(EXIT_FAILURE);
                }
        }
}


static void init_device(void)
{
        printf("initiating device\n");
        struct v4l2_capability cap;
        struct v4l2_cropcap cropcap;
        struct v4l2_crop crop;
        struct v4l2_format fmt;
        unsigned int min;

        if (-1 == xioctl(fd,VIdioC_QUERYCAP,&cap)) {  // gets information about driver and harware capabilities
                if (EINVAL == errno) {                  // driver is not compatible with specifications
                        fprintf(stderr,"%s is no V4L2 device\n",dev_name);
                        exit(EXIT_FAILURE);
                } else {
                        errno_exit("VIdioC_QUERYCAP");
                }
        }

        if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
                fprintf(stderr,"%s is no video capture device\n",dev_name);
                exit(EXIT_FAILURE);
        }
        if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
                fprintf(stderr,"%s does not support streaming I/O\n",dev_name);
                exit(EXIT_FAILURE);
        }

        /* Select video input,video standard and tune here. */

        CLEAR(cropcap);

        cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

        if (0 == xioctl(fd,VIdioC_CROPCAP,&cropcap)) {  // used to get cropping limits,pixel aspects,... fill in type field and get all this information back
                crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                crop.c = cropcap.defrect; /* reset to default */

                if (-1 == xioctl(fd,VIdioC_S_CROP,&crop)) { // get cropping rectangle
                        switch (errno) {
                        case EINVAL:
                                printf("EINVAL in VIdioC_S_CROP\n");
                                /* Cropping not supported. */
                                break;
                        default:
                                printf("other error in VIdioC_S_CROP\n");
                                /* Errors ignored. */
                                break;
                        }
                }
        } else {
                /* Errors ignored. */
        }


        CLEAR(fmt);   // set the format of the v4l2 video

        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;

        if (-1 == xioctl(fd,fmt.type field is invalid\n");
                          break;

                  case EBADR:
                          printf("EBADR\n");
                          break;

                  case EBUSY:
                          printf("EBUSY\n");
                          break;

                  /* fall through */
                }
                errno_exit("VIdioC_S_FMT");
        }

        /*
        if (force_format) {
                  printf("Set RGB888\r\n");

                fmt.fmt.pix.width       = 640; //replace
                fmt.fmt.pix.height      = 483; //replace
                fmt.fmt.pix.pixelformat = SDE_PIX_FMT_RGB_888; //replace
                fmt.fmt.pix.field       = V4L2_FIELD_ANY;

                printf("fmt fields adjusted\n");
                printf("fmt.type = %d\n",fmt.type);

                if (-1 == xioctl(fd,&fmt)){
                          switch (errno) {
                          case EAGAIN:
                                  printf("EAGAIN\n");
                                  break;

                          case EINVAL:
                                  printf("EINVAL,fmt.type field is invalid\n");
                                  break;

                          case EBADR:
                                  printf("EBADR\n");
                                  break;

                          case EBUSY:
                                  printf("EBUSY\n");
                                  break;

                          // fall through
                        }
                        errno_exit("VIdioC_S_FMT");
                }
                // Note VIdioC_S_FMT may change width and height.
        } else {
                // Preserve original settings as set by v4l2-ctl for example
                if (-1 == xioctl(fd,&fmt))
                        errno_exit("VIdioC_G_FMT");
        }
        */

        /* Buggy driver paranoia. */
        min = fmt.fmt.pix.width * 2;

        if (fmt.fmt.pix.bytesperline < min)
                fmt.fmt.pix.bytesperline = min;

        min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;

        if (fmt.fmt.pix.sizeimage < min)
                fmt.fmt.pix.sizeimage = min;

        //init_mmap();

        init_userp(fmt.fmt.pix.sizeimage);

        printf("fmt.fmt.pix.width = %d\n",fmt.fmt.pix.pixelformat);

        printf("device inititiated\n");
}


static void close_device(void)
{
        printf("closing device\n");
        if (-1 == close(fd))
                errno_exit("close");

        fd = -1;
        printf("device closed\n");
}


/*
struct stat {
               dev_t     st_dev;         ID of device containing file
               ino_t     st_ino;         Inode number
               mode_t    st_mode;        File type and mode
               nlink_t   st_nlink;       Number of hard links
               uid_t     st_uid;         User ID of owner
               gid_t     st_gid;         Group ID of owner
               dev_t     st_rdev;        Device ID (if special file)
               off_t     st_size;        Total size,in bytes
               blksize_t st_blksize;     Block size for filesystem I/O
               blkcnt_t  st_blocks;      Number of 512B blocks allocated

                  Since Linux 2.6,the kernel supports nanosecond
                  precision for the following timestamp fields.
                  For the details before Linux 2.6,see NOTES.

               struct timespec st_atim;  Time of last access
               struct timespec st_mtim;  Time of last modification
               struct timespec st_ctim;  Time of last status change

           #define st_atime st_atim.tv_sec      Backward compatibility
           #define st_mtime st_mtim.tv_sec
           #define st_ctime st_ctim.tv_sec
           };
*/

static void open_device(void)
{
        printf("openening device\n");
        struct stat st;

        if (-1 == stat(dev_name,&st)) {                              // stat() returns info about file into struct
                fprintf(stderr,"Cannot identify '%s': %d,dev_name,strerror(errno));
                exit(EXIT_FAILURE);
        }

        if (!S_ISCHR(st.st_mode)) {
                fprintf(stderr,"%s is no device\n",dev_name);
                exit(EXIT_FAILURE);
        }

        fd = open(dev_name,O_RDWR /* required */ | O_NONBLOCK,0);   // open the file dev/video0,returns a file descriptor

        // if fd == -1,the file Could not be opened.
        if (-1 == fd) {
                fprintf(stderr,"Cannot open '%s': %d,strerror(errno));
                exit(EXIT_FAILURE);
        }
        printf("device opened\n");
}


int main(int argc,char **argv)
{
        printf("main begins\n");
        dev_name = "/dev/video0";

        for (;;) {
                printf("back here\n");
                break;
        }
        force_format = 1;
        open_device();
        init_device();
        start_capturing();
        mainloop();
        stop_capturing();
        uninit_device();
        close_device();
        fprintf(stderr,"\n");
        return 0;
}

在终端中完整打印:

main begins
back here
openening device
device opened
initiating device
fmt.fmt.pix.width = 0
fmt.fmt.pix.pixelformat = 0
Set RGB888
fmt fields adjusted
fmt.type = 1
EINVAL,Invalid argument

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。