V4L2采集yuv视频花屏:Linux视频采集与编码(一)

    xiaoxiao2021-04-14  63

    V4L2采集yuv视频花屏:Linux视频采集与编码(一)

    标签: linuxvideobufferiostructnull 16179人阅读 评论(42) 收藏 举报 本文章已收录于: 嵌入式开发知识库 分类: Linux(2) 作者同类文章 X •V4L2视频采集与H.264编码源码大放送:Linux视频采集与编码(三) •YUYV编码成h.264:Linux视频采集与编码(二)

    这两天在Linux下用V4L2采集yuv视频然后用x264编码成h.264文件。

    我将yuv视频保存到文件中,然后用pyuv播放器播放它,悲剧的是播放出来的视频花屏了。

    如下所示:

    我采集视频的参数为:

    尺寸:640 * 480

    YUV格式:YUYV即YUV422

    我一直以为是我代码写错了,因为采集视频的程序我是参考V4L2官方示例代码的,并且我把官方示例代码来运行,发现采集的视频也是花屏的。然后我又猜想可能是我摄像头不能采集数据吗?可是我下载好几个camera都可以正常的拍照,录制视频。这样纠结了好久好久。直到我的手开始犯贱,我把pyuv播放器 Format中的 Interleaved 复选框勾起来了,奇迹出现了。pyuv上清清楚楚的显示出了我录制的视频 Orz

    后来认真看代码发现我的设置中有这么一句:fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 意思就是采集数据的时候使用的是隔行扫描的方式,也就是说我将采集到的yuv写到文件中的方式是用隔行扫描的方式保存。

    于是如果不将 Interleaved复选框勾起来,播放器就不能正常的播放你的yuv文件。

    下面是正常时候显示的图像:

    嘿嘿,这是本人靓照 ^_^

    yuv视频采集正常了,可是用x264编码出来的视频还是花屏到不堪入目!!!

    这个是怎么办呢?请看我下一篇博文《YUYV编码成h.264:Linux视频采集与编码(二)》

    附上V4L2视频采集代码:

    [cpp] view plain copy print ? /*  *  V4L2 video capture example  *  *  This program can be used and distributed without restrictions.  */    #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 <malloc.h>  #include <sys/stat.h>  #include <sys/types.h>  #include <sys/time.h>  #include <sys/mman.h>  #include <sys/ioctl.h>    #include <asm/types.h>          /* for videodev2.h */    #include <linux/videodev2.h>    #define CLEAR(x) memset (&(x), 0, sizeof (x))    typedef enum {      IO_METHOD_READ, IO_METHOD_MMAP, IO_METHOD_USERPTR,  } io_method;    struct buffer {      void * start;      size_t length;  };    static char * dev_name = NULL;  static io_method io = IO_METHOD_MMAP;  static int fd = -1;  struct buffer * buffers = NULL;  static unsigned int n_buffers = 0;    FILE *fp;  char *filename = "test.yuv\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 fd, int request, void * arg) {      int r;        do {          r = ioctl(fd, request, arg);      } while (-1 == r && EINTR == errno);        return r;  }    static void process_image(const void * p, int size) {      fwrite(p, size, 1, fp);  }    static int read_frame(void) {      struct v4l2_buffer buf;      unsigned int i;        switch (io) {      case IO_METHOD_READ:          if (-1 == read(fd, buffers[0].start, buffers[0].length)) {              switch (errno) {              case EAGAIN:                  return 0;                case EIO:                  /* Could ignore EIO, see spec. */                  /* fall through */              default:                  errno_exit("read");              }          }            process_image(buffers[0].start, buffers[0].length);            break;        case IO_METHOD_MMAP:          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.length);            if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))              errno_exit("VIDIOC_QBUF");            break;        case IO_METHOD_USERPTR:          CLEAR(buf);            buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;          buf.memory = V4L2_MEMORY_USERPTR;            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");              }          }            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.length);            if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))              errno_exit("VIDIOC_QBUF");            break;      }        return 1;  }    static void mainloop(void) {      unsigned int count;        count = 100;        while (count-- > 0) {          for (;;) {              fd_set fds;              struct timeval tv;              int r;                FD_ZERO(&fds);              FD_SET(fd, &fds);                /* Timeout. */              tv.tv_sec = 2;              tv.tv_usec = 0;                r = select(fd + 1, &fds, NULL, NULL, &tv);                if (-1 == r) {                  if (EINTR == errno)                      continue;                    errno_exit("select");              }                if (0 == r) {                  fprintf(stderr, "select timeout/n");                  exit(EXIT_FAILURE);              }                if (read_frame())                  break;                /* EAGAIN - continue select loop. */          }      }  }    static void stop_capturing(void) {      enum v4l2_buf_type type;        switch (io) {      case IO_METHOD_READ:          /* Nothing to do. */          break;        case IO_METHOD_MMAP:      case IO_METHOD_USERPTR:          type = V4L2_BUF_TYPE_VIDEO_CAPTURE;            if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))              errno_exit("VIDIOC_STREAMOFF");            break;      }  }    static void start_capturing(void) {      unsigned int i;      enum v4l2_buf_type type;        switch (io) {      case IO_METHOD_READ:          /* Nothing to do. */          break;        case IO_METHOD_MMAP:          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, VIDIOC_QBUF, &buf))                  errno_exit("VIDIOC_QBUF");          }            type = V4L2_BUF_TYPE_VIDEO_CAPTURE;            if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))              errno_exit("VIDIOC_STREAMON");            break;        case IO_METHOD_USERPTR:          for (i = 0; i < n_buffers; ++i) {              struct v4l2_buffer buf;                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;                if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))                  errno_exit("VIDIOC_QBUF");          }            type = V4L2_BUF_TYPE_VIDEO_CAPTURE;            if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))              errno_exit("VIDIOC_STREAMON");            break;      }  }    static void uninit_device(void) {      unsigned int i;        switch (io) {      case IO_METHOD_READ:          free(buffers[0].start);          break;        case IO_METHOD_MMAP:          for (i = 0; i < n_buffers; ++i)              if (-1 == munmap(buffers[i].start, buffers[i].length))                  errno_exit("munmap");          break;        case IO_METHOD_USERPTR:          for (i = 0; i < n_buffers; ++i)              free(buffers[i].start);          break;      }        free(buffers);  }    static void init_read(unsigned int buffer_size) {      buffers = calloc(1, sizeof(*buffers));        if (!buffers) {          fprintf(stderr, "Out of memory/n");          exit(EXIT_FAILURE);      }        buffers[0].length = buffer_size;      buffers[0].start = malloc(buffer_size);        if (!buffers[0].start) {          fprintf(stderr, "Out of memory/n");          exit(EXIT_FAILURE);      }  }    static void init_mmap(void) {      struct v4l2_requestbuffers req;        CLEAR(req);        req.count = 4;      req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;      req.memory = V4L2_MEMORY_MMAP;        if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {          if (EINVAL == errno) {              fprintf(stderr, "%s does not support "                      "memory mapping/n", dev_name);              exit(EXIT_FAILURE);          } else {              errno_exit("VIDIOC_REQBUFS");          }      }        if (req.count < 2) {          fprintf(stderr, "Insufficient buffer memory on %s/n", dev_name);          exit(EXIT_FAILURE);      }        buffers = calloc(req.count, sizeof(*buffers));        if (!buffers) {          fprintf(stderr, "Out of memory/n");          exit(EXIT_FAILURE);      }        for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {          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");      }  }    static void init_userp(unsigned int buffer_size) {      struct v4l2_requestbuffers req;      unsigned int page_size;        page_size = getpagesize();      buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1);        CLEAR(req);        req.count = 4;      req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;      req.memory = V4L2_MEMORY_USERPTR;        if (-1 == xioctl(fd, VIDIOC_REQBUFS, &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 = memalign(/* boundary */page_size,                  buffer_size);            if (!buffers[n_buffers].start) {              fprintf(stderr, "Out of memory/n");              exit(EXIT_FAILURE);          }      }  }    static void init_device(void) {      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)) {          if (EINVAL == errno) {              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);      }        switch (io) {      case IO_METHOD_READ:          if (!(cap.capabilities & V4L2_CAP_READWRITE)) {              fprintf(stderr, "%s does not support read i/o/n", dev_name);              exit(EXIT_FAILURE);          }            break;        case IO_METHOD_MMAP:      case IO_METHOD_USERPTR:          if (!(cap.capabilities & V4L2_CAP_STREAMING)) {              fprintf(stderr, "%s does not support streaming i/o/n", dev_name);              exit(EXIT_FAILURE);          }            break;      }        /* Select video input, video standard and tune here. */        CLEAR(cropcap);        cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;        if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {          crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;          crop.c = cropcap.defrect; /* reset to default */            if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {              switch (errno) {              case EINVAL:                  /* Cropping not supported. */                  break;              default:                  /* Errors ignored. */                  break;              }          }      } else {          /* Errors ignored. */      }        CLEAR(fmt);        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;      fmt.fmt.pix.width = 640;      fmt.fmt.pix.height = 480;      fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;      fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;        if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))          errno_exit("VIDIOC_S_FMT");        /* Note VIDIOC_S_FMT may change width and height. */        /* 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;        switch (io) {      case IO_METHOD_READ:          init_read(fmt.fmt.pix.sizeimage);          break;        case IO_METHOD_MMAP:          init_mmap();          break;        case IO_METHOD_USERPTR:          init_userp(fmt.fmt.pix.sizeimage);          break;      }  }    static void close_device(void) {      if (-1 == close(fd))          errno_exit("close");        fd = -1;  }    static void open_device(void) {      struct stat st;        if (-1 == stat(dev_name, &st)) {          fprintf(stderr, "Cannot identify '%s': %d, %s/n", dev_name, errno,                  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);        if (-1 == fd) {          fprintf(stderr, "Cannot open '%s': %d, %s/n", dev_name, errno,                  strerror(errno));          exit(EXIT_FAILURE);      }  }    static void usage(FILE * fp, int argc, char ** argv) {      fprintf(fp, "Usage: %s [options]/n/n"              "Options:/n"              "-d | --device name   Video device name [/dev/video]/n"              "-h | --help          Print this message/n"              "-m | --mmap          Use memory mapped buffers/n"              "-r | --read          Use read() calls/n"              "-u | --userp         Use application allocated buffers/n"              "", argv[0]);  }    static const char short_options[] = "d:hmru";    static const struct option long_options[] = { { "device", required_argument,          NULL, 'd' }, { "help", no_argument, NULL, 'h' }, { "mmap", no_argument,          NULL, 'm' }, { "read", no_argument, NULL, 'r' }, { "userp", no_argument,          NULL, 'u' }, { 0, 0, 0, 0 } };    int main(int argc, char ** argv) {      dev_name = "/dev/video0";        for (;;) {          int index;          int c;            c = getopt_long(argc, argv, short_options, long_options, &index);            if (-1 == c)              break;            switch (c) {          case 0: /* getopt_long() flag */              break;            case 'd':              dev_name = optarg;              break;            case 'h':              usage(stdout, argc, argv);              exit(EXIT_SUCCESS);            case 'm':              io = IO_METHOD_MMAP;              break;            case 'r':              io = IO_METHOD_READ;              break;            case 'u':              io = IO_METHOD_USERPTR;              break;            default:              usage(stderr, argc, argv);              exit(EXIT_FAILURE);          }      }        open_device();        init_device();        start_capturing();        fp = fopen(filename, "wa+");      mainloop();      fclose(fp);        stop_capturing();        uninit_device();        close_device();        exit(EXIT_SUCCESS);        return 0;  }   /* * V4L2 video capture example * * This program can be used and distributed without restrictions. */ #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 <malloc.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/time.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <asm/types.h> /* for videodev2.h */ #include <linux/videodev2.h> #define CLEAR(x) memset (&(x), 0, sizeof (x)) typedef enum { IO_METHOD_READ, IO_METHOD_MMAP, IO_METHOD_USERPTR, } io_method; struct buffer { void * start; size_t length; }; static char * dev_name = NULL; static io_method io = IO_METHOD_MMAP; static int fd = -1; struct buffer * buffers = NULL; static unsigned int n_buffers = 0; FILE *fp; char *filename = "test.yuv\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 fd, int request, void * arg) { int r; do { r = ioctl(fd, request, arg); } while (-1 == r && EINTR == errno); return r; } static void process_image(const void * p, int size) { fwrite(p, size, 1, fp); } static int read_frame(void) { struct v4l2_buffer buf; unsigned int i; switch (io) { case IO_METHOD_READ: if (-1 == read(fd, buffers[0].start, buffers[0].length)) { switch (errno) { case EAGAIN: return 0; case EIO: /* Could ignore EIO, see spec. */ /* fall through */ default: errno_exit("read"); } } process_image(buffers[0].start, buffers[0].length); break; case IO_METHOD_MMAP: 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.length); if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) errno_exit("VIDIOC_QBUF"); break; case IO_METHOD_USERPTR: CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_USERPTR; 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"); } } 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.length); if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) errno_exit("VIDIOC_QBUF"); break; } return 1; } static void mainloop(void) { unsigned int count; count = 100; while (count-- > 0) { for (;;) { fd_set fds; struct timeval tv; int r; FD_ZERO(&fds); FD_SET(fd, &fds); /* Timeout. */ tv.tv_sec = 2; tv.tv_usec = 0; r = select(fd + 1, &fds, NULL, NULL, &tv); if (-1 == r) { if (EINTR == errno) continue; errno_exit("select"); } if (0 == r) { fprintf(stderr, "select timeout/n"); exit(EXIT_FAILURE); } if (read_frame()) break; /* EAGAIN - continue select loop. */ } } } static void stop_capturing(void) { enum v4l2_buf_type type; switch (io) { case IO_METHOD_READ: /* Nothing to do. */ break; case IO_METHOD_MMAP: case IO_METHOD_USERPTR: type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type)) errno_exit("VIDIOC_STREAMOFF"); break; } } static void start_capturing(void) { unsigned int i; enum v4l2_buf_type type; switch (io) { case IO_METHOD_READ: /* Nothing to do. */ break; case IO_METHOD_MMAP: 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, VIDIOC_QBUF, &buf)) errno_exit("VIDIOC_QBUF"); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) errno_exit("VIDIOC_STREAMON"); break; case IO_METHOD_USERPTR: for (i = 0; i < n_buffers; ++i) { struct v4l2_buffer buf; 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; if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) errno_exit("VIDIOC_QBUF"); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) errno_exit("VIDIOC_STREAMON"); break; } } static void uninit_device(void) { unsigned int i; switch (io) { case IO_METHOD_READ: free(buffers[0].start); break; case IO_METHOD_MMAP: for (i = 0; i < n_buffers; ++i) if (-1 == munmap(buffers[i].start, buffers[i].length)) errno_exit("munmap"); break; case IO_METHOD_USERPTR: for (i = 0; i < n_buffers; ++i) free(buffers[i].start); break; } free(buffers); } static void init_read(unsigned int buffer_size) { buffers = calloc(1, sizeof(*buffers)); if (!buffers) { fprintf(stderr, "Out of memory/n"); exit(EXIT_FAILURE); } buffers[0].length = buffer_size; buffers[0].start = malloc(buffer_size); if (!buffers[0].start) { fprintf(stderr, "Out of memory/n"); exit(EXIT_FAILURE); } } static void init_mmap(void) { struct v4l2_requestbuffers req; CLEAR(req); req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { if (EINVAL == errno) { fprintf(stderr, "%s does not support " "memory mapping/n", dev_name); exit(EXIT_FAILURE); } else { errno_exit("VIDIOC_REQBUFS"); } } if (req.count < 2) { fprintf(stderr, "Insufficient buffer memory on %s/n", dev_name); exit(EXIT_FAILURE); } buffers = calloc(req.count, sizeof(*buffers)); if (!buffers) { fprintf(stderr, "Out of memory/n"); exit(EXIT_FAILURE); } for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { 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"); } } static void init_userp(unsigned int buffer_size) { struct v4l2_requestbuffers req; unsigned int page_size; page_size = getpagesize(); buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1); CLEAR(req); req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_USERPTR; if (-1 == xioctl(fd, VIDIOC_REQBUFS, &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 = memalign(/* boundary */page_size, buffer_size); if (!buffers[n_buffers].start) { fprintf(stderr, "Out of memory/n"); exit(EXIT_FAILURE); } } } static void init_device(void) { 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)) { if (EINVAL == errno) { 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); } switch (io) { case IO_METHOD_READ: if (!(cap.capabilities & V4L2_CAP_READWRITE)) { fprintf(stderr, "%s does not support read i/o/n", dev_name); exit(EXIT_FAILURE); } break; case IO_METHOD_MMAP: case IO_METHOD_USERPTR: if (!(cap.capabilities & V4L2_CAP_STREAMING)) { fprintf(stderr, "%s does not support streaming i/o/n", dev_name); exit(EXIT_FAILURE); } break; } /* Select video input, video standard and tune here. */ CLEAR(cropcap); cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) { crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; crop.c = cropcap.defrect; /* reset to default */ if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) { switch (errno) { case EINVAL: /* Cropping not supported. */ break; default: /* Errors ignored. */ break; } } } else { /* Errors ignored. */ } CLEAR(fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = 640; fmt.fmt.pix.height = 480; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) errno_exit("VIDIOC_S_FMT"); /* Note VIDIOC_S_FMT may change width and height. */ /* 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; switch (io) { case IO_METHOD_READ: init_read(fmt.fmt.pix.sizeimage); break; case IO_METHOD_MMAP: init_mmap(); break; case IO_METHOD_USERPTR: init_userp(fmt.fmt.pix.sizeimage); break; } } static void close_device(void) { if (-1 == close(fd)) errno_exit("close"); fd = -1; } static void open_device(void) { struct stat st; if (-1 == stat(dev_name, &st)) { fprintf(stderr, "Cannot identify '%s': %d, %s/n", dev_name, errno, 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); if (-1 == fd) { fprintf(stderr, "Cannot open '%s': %d, %s/n", dev_name, errno, strerror(errno)); exit(EXIT_FAILURE); } } static void usage(FILE * fp, int argc, char ** argv) { fprintf(fp, "Usage: %s [options]/n/n" "Options:/n" "-d | --device name Video device name [/dev/video]/n" "-h | --help Print this message/n" "-m | --mmap Use memory mapped buffers/n" "-r | --read Use read() calls/n" "-u | --userp Use application allocated buffers/n" "", argv[0]); } static const char short_options[] = "d:hmru"; static const struct option long_options[] = { { "device", required_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, { "mmap", no_argument, NULL, 'm' }, { "read", no_argument, NULL, 'r' }, { "userp", no_argument, NULL, 'u' }, { 0, 0, 0, 0 } }; int main(int argc, char ** argv) { dev_name = "/dev/video0"; for (;;) { int index; int c; c = getopt_long(argc, argv, short_options, long_options, &index); if (-1 == c) break; switch (c) { case 0: /* getopt_long() flag */ break; case 'd': dev_name = optarg; break; case 'h': usage(stdout, argc, argv); exit(EXIT_SUCCESS); case 'm': io = IO_METHOD_MMAP; break; case 'r': io = IO_METHOD_READ; break; case 'u': io = IO_METHOD_USERPTR; break; default: usage(stderr, argc, argv); exit(EXIT_FAILURE); } } open_device(); init_device(); start_capturing(); fp = fopen(filename, "wa+"); mainloop(); fclose(fp); stop_capturing(); uninit_device(); close_device(); exit(EXIT_SUCCESS); return 0; }

    顶 3 踩 0     上一篇'\0'的悲剧 下一篇YUYV编码成h.264:Linux视频采集与编码(二)

    我的同类文章

    Linux(2) http://blog.csdn.net •V4L2视频采集与H.264编码源码大放送:Linux视频采集与编码(三)2012-05-03阅读18600 •YUYV编码成h.264:Linux视频采集与编码(二)2012-05-01阅读12720
    转载请注明原文地址: https://ju.6miu.com/read-670616.html

    最新回复(0)