V4L2抓取YUV图像

来源:互联网 发布:python snmp 交换机 编辑:程序博客网 时间:2024/05/03 06:21

      • 一 V4L2简介
      • 二 实现过程
      • 三 代码范例

本文实现了一个简单应用,通过V4L2驱动,抓取usb摄像头的YUV图像,运行在Linux Mint 17上, 代码参考自 https://linuxtv.org/。usb摄像头型号为logitech c170,参数如下

传感器 CMOS 像素 物理像素130W,500万(软件增强) 捕获幅面 1024*768 视像解像度(分辨率) 1024*768 最大帧数 30帧/秒 接口 USB 2.0 麦克风 内置 驱动 免驱

一. V4L2简介

V4L2(video 4 linux 2)
V4L2有一段历史了。大约在1998的秋天,它的光芒第一次出现在Bill Dirks 的眼中。经过长足的发展,它于2002年11 月,发布2.5.46 时,融入了内核主干之中。然而直到今天,仍有一部分内核驱动不支持新的API,这种新旧API 的转换工作仍在进行。同时,V4L2 API也在发展,并在2.6.18 版本中进行了一些重大的改变。支持V4L2的应用依旧相对较少。V4L2在设计时,是要支持很多广泛的设备的,它们之中只有一部分在本质上是真正的视频设备:
可以支持多种设备,它可以有以下几种接口:
1. 视频采集接口(video capture interface):这种应用的设备可以是高频头或者摄像头.V4L2的最初设计就是应用于这种功能的.
2. 视频输出接口(video output interface):可以驱动计算机的外围视频图像设备–像可以输出电视信号格式的设备.
3. 直接传输视频接口(video overlay interface):它的主要工作是把从视频采集设备采集过来的信号直接输出到输出设备之上,而不用经过系统的CPU.
4. 视频间隔消隐信号接口(VBI interface):它可以使应用可以访问传输消隐期的视频信号.
5. 收音机接口(radio interface):可用来处理从AM或FM高频头设备接收来的音频流.

二. 实现过程

  • 准备环境
    把usb摄像头插入笔记本usb口,可以在/dev目录下看到设备名,例如我的是/dev/video0
  • 编译代码
$gcc capture.c -o xcapture
  • 执行
$./xcapture -d /dev/video0
  • 查看yuv文件
    保存下来的文件名字叫test.yuv,用pyuv打开。pyuv下载地址:
    http://dsplab.diei.unipg.it/~baruffa/dvbt/binaries/player/lin32/pyuv_0.5-1_i386.deb

打开后如图所示配置后就能正确看到图像
这里写图片描述

这里写图片描述

三. 代码范例

/* *  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;static int fb_fd = -1;static FILE *save_fd = NULL;static voiderrno_exit(const char *s){    fprintf (stderr, "%s error %d, %s\n", s, errno, strerror (errno));    exit (EXIT_FAILURE);}static intxioctl(int fd, int request, void *arg){    int r;    do r = ioctl (fd, request, arg);    while (-1 == r && EINTR == errno);    return r;}static voidprocess_image(const void *p, size_t length){    fputc ('.', stdout);    fwrite(p, sizeof(char), length, save_fd);    fflush (stdout);}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, buffers[buf.index].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 voiduninit_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 voidclose_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 optionlong_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/video";    save_fd = fopen("test.yuv", "w");    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 ();    mainloop ();    stop_capturing ();    uninit_device ();    close_device ();    fclose(save_fd);    exit (EXIT_SUCCESS);    return 0;}

以上代码参考自官方的capture.c,可以自行下载,这里面只添加了一个文件句柄 save_fd,用来保存图像数据。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 泰迪坐车吐了怎么办 小孩感冒流鼻涕带血怎么办 孩子鼻子流鼻涕有血丝怎么办 鼻子过敏流鼻涕有血丝怎么办 孕妇感冒头痛鼻涕带血怎么办 孕妇感冒鼻塞鼻涕带血怎么办 孕晚期感冒流鼻涕打喷嚏怎么办 孕晚期感冒鼻塞流鼻涕怎么办 怀孕初期鼻涕一直流怎么办 孩子一直流鼻水怎么办 9个月宝宝流鼻涕怎么办 8个月婴儿流鼻涕怎么办 3岁宝宝鼻塞咳嗽怎么办 又感冒又咳嗽了怎么办 鼻塞有一个月了怎么办 感冒一直流清水鼻涕怎么办 孩子受凉流清水鼻涕怎么办 一遇冷空气就打喷嚏流鼻涕怎么办 打喷嚏鼻塞流清鼻涕怎么办 哺乳期鼻子不通气有鼻涕怎么办 宝宝热伤风流清鼻涕怎么办 哺乳期感冒流鼻涕怎么办最有效 小孩睡觉太晚了怎么办 孩子晚上睡觉不安稳怎么办 月子里宝宝睡觉不安稳怎么办 月子宝宝睡觉不安稳怎么办 孩子老是流黄鼻涕怎么办 孕妇流黄鼻涕怎么办速效办法 孕妇感冒流黄鼻涕怎么办 孕妇有黄痰和黄鼻涕怎么办 孕妇感冒了流黄鼻涕怎么办 怀孕感冒了怎么办鼻塞流鼻涕 怀孕初期感冒了怎么办鼻塞流鼻涕 怀孕9个月流鼻涕怎么办 怀孕5个月流鼻涕怎么办 小孩老是流黄鼻涕口臭怎么办 狗狗有食欲流黄鼻涕拉稀怎么办 小孩流黄鼻涕咳嗽怎么办 小狗感冒了一直打喷嚏怎么办 眼干眼屎多模糊怎么办 宝宝眼睛上火眼屎多怎么办