免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5604 | 回复: 2
打印 上一主题 下一主题

[学习分享] Z301摄像头linux下采集图片程序 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-05-27 23:52 |只看该作者 |倒序浏览
本帖最后由 chenyx 于 2013-05-28 07:31 编辑

Z301摄像头linux下采集图片程序
以下为中星微z301摄像头在linux下的应用程序。现在内核基本包含z301摄像头驱动,下列为应用程序,将USB摄像头插在开发板上,若有打印如下,说明内核包含此摄像头驱动,并且创建/dev/video2设备。(将下列应用程序的设备修改为/dev/video2)
/dev/videousb 1-1.2: new full speed USB device using s3c2410-ohci and address3
usb 1-1.2: New USB device found, idVendor=0ac8, idProduct=301b
usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 1-1.2: Product: PC Camera
usb 1-1.2: Manufacturer: Vimicro Corp.
gspca: probing 0ac8:301b
zc3xx: probe 2wr ov vga 0x0000
zc3xx: probe sensor -> 0011
zc3xx: Find Sensor HV7131R
input: zc3xx as /devices/platform/s3c2410-ohci/usb1/1-1/1-1.2/input/input1
gspca: video2 created


应用程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h>
#include <fcntl.h>
#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>
#include <linux/videodev2.h>
#define CLEAR(x) memset (&(x), 0, sizeof (x))
struct buffer {
        void * start;
        size_t length;
};
static char * dev_name = "/dev/video2";//摄像头设备名
static int fd = -1;
struct buffer * buffers = NULL;
static unsigned int n_buffers = 0;
FILE *file_fd;
static unsigned long file_length;
static unsigned char *file_name;
//////////////////////////////////////////////////////
//获取一帧数据
//////////////////////////////////////////////////////
static int read_frame(void)
{
        struct v4l2_buffer buf;
        unsigned int i;
        CLEAR (buf);
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        /*8.出队列以取得已采集数据的帧缓冲,取得原始采集数据。VIDIOC_DQBUF*/
        int ff = ioctl(fd, VIDIOC_DQBUF, &buf);
        if (ff < 0)
                printf("failture\n"); //出列采集的帧缓冲
        assert(buf.index < n_buffers);
        printf("buf.index dq is %d,\n", buf.index);
        fwrite(buffers[buf.index].start, buffers[buf.index].length, 1, file_fd); //将其写入文件中
        /*9.将缓冲重新入队列尾,这样可以循环采集。VIDIOC_QBUF*/
        ff = ioctl(fd, VIDIOC_QBUF, &buf); //再将其入列
        if (ff < 0)//把数据从缓存中读取出来
                printf("failture VIDIOC_QBUF\n");
        return 1;
}
int main(int argc, char ** argv)
{
        struct v4l2_capability cap;
        struct v4l2_format fmt;
        unsigned int i;
        enum v4l2_buf_type type;
        file_fd = fopen("test-mmap.jpg", "w");//图片文件名
        /*1.打开设备文件。 int fd=open(”/dev/video0″,O_RDWR);*********/
        fd = open(dev_name, O_RDWR /* required */| O_NONBLOCK, 0);//打开设备
        /*2.取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。VIDIOC_QUERYCAP,struct v4l2_capability*/
        int ff = ioctl(fd, VIDIOC_QUERYCAP, &cap);//获取摄像头参数
        if (ff < 0)
                printf("failture VIDIOC_QUERYCAP\n");
        /*3.设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。*/
        struct v4l2_fmtdesc fmt1;
        int ret;
        memset(&fmt1, 0, sizeof(fmt1));
        fmt1.index = 0;
        fmt1.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        //获取当前驱动支持的视频格式
        printf("we are here11\n");
        while ((ret = ioctl(fd, VIDIOC_ENUM_FMT, &fmt1)) == 0)
        {
                fmt1.index++;
                printf("{ pixelformat = '%c%c%c%c', description = '%s' }\n",
                                fmt1.pixelformat & 0xFF, (fmt1.pixelformat >> 8) & 0xFF,
                                (fmt1.pixelformat >> 16) & 0xFF,
                                (fmt1.pixelformat >> 24) & 0xFF, fmt1.description);
        }
        //帧的格式,比如宽度,高度等
        CLEAR (fmt);
        printf("we are here22\n");
        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE
        fmt.fmt.pix.width = 640;//宽,必须是16的倍数
        fmt.fmt.pix.height = 480;////高,必须是16的倍数
        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;//视频数据存储类型//V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_YVU420;//V4L2_PIX_FMT_YUYV;
        fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

        //设置当前驱动的频捕获格式
        ff = ioctl(fd, VIDIOC_S_FMT, &fmt);
        if (ff < 0)
                printf("failture VIDIOC_S_FMT\n");
        //计算图片大小
        printf("we are here33\n");
        file_length = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
        /*4.向驱动申请帧缓冲,一般不超过5个。struct v4l2_requestbuffers*/
        struct v4l2_requestbuffers req;
        CLEAR (req);
        req.count = 1;//缓存数量,也就是说在缓存队列里保持多少张照片
        req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        req.memory = V4L2_MEMORY_MMAP;//或V4L2_MEMORY_USERPTR

        ff = ioctl(fd, VIDIOC_REQBUFS, &req); //申请缓冲,count是申请的数量
        if (ff < 0)
                printf("failture VIDIOC_REQBUFS\n");
        if (req.count < 1)
                printf("Insufficient buffer memory\n");
        buffers = (struct buffer*) calloc(req.count, sizeof(*buffers));//内存中建立对应空间
        printf("we are here44\n");

        /*5.将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。mmap*/
        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;
                //把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址
                if (-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf)) //映射用户空间
                        printf("VIDIOC_QUERYBUF error\n");
                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);//通过mmap建立映射关系,返回映射区的起始地址
                if (MAP_FAILED == buffers[n_buffers].start)
                        printf("mmap failed\n");
        }
        printf("we are here55\n");
        /*6.将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer*/
        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 == ioctl(fd, VIDIOC_QBUF, &buf))//申请到的缓冲进入列队
                        printf("VIDIOC_QBUF failed\n");
        }
        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        /*7.开始视频的采集。VIDIOC_STREAMON*/
        if (-1 == ioctl(fd, VIDIOC_STREAMON, &type)) //开始捕捉图像数据
                printf("VIDIOC_STREAMON failed\n");
        for (;;) //这一段涉及到异步IO
        {
                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);//判断是否可读(即摄像头是否准备好),tv是定时
                if (-1 == r)
                {
                        if (EINTR == errno)
                                continue;
                        printf("select err\n");

                }
                if (0 == r) {
                        fprintf(stderr, "select timeout\n");
                        exit(EXIT_FAILURE);
                }
                if (read_frame())//如果可读,执行read_frame ()函数,并跳出循环
                        break;
        }
        unmap:
        for (i = 0; i < n_buffers; ++i)
                if (-1 == munmap(buffers->start, buffers->length))
                        printf("munmap error");
        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        /*10.停止视频的采集。VIDIOC_STREAMOFF*/
        if (-1 == ioctl(fd, VIDIOC_STREAMOFF, &type))
                printf("VIDIOC_STREAMOFF");
        /*11.关闭视频设备。close(fd);*/
        close(fd);
        fclose(file_fd);
        exit(EXIT_SUCCESS);
        return 0;
}

编译执行:
将上述程序复制到capture.c,编译arm-linux-gcc capture.c –o capture。
将应用程序capture放到开发板上执行即可,即./capture。
附图片一张:

论坛徽章:
381
CU十二周年纪念徽章
日期:2014-01-04 22:46:58CU大牛徽章
日期:2013-03-13 15:32:35CU大牛徽章
日期:2013-03-13 15:38:15CU大牛徽章
日期:2013-03-13 15:38:52CU大牛徽章
日期:2013-03-14 14:08:55CU大牛徽章
日期:2013-04-17 11:17:19CU大牛徽章
日期:2013-04-17 11:17:32CU大牛徽章
日期:2013-04-17 11:17:37CU大牛徽章
日期:2013-04-17 11:17:42CU大牛徽章
日期:2013-04-17 11:17:47CU大牛徽章
日期:2013-04-17 11:17:52CU大牛徽章
日期:2013-04-17 11:17:56
2 [报告]
发表于 2013-05-28 07:32 |只看该作者
这个应该发到嵌入式开发版块

论坛徽章:
0
3 [报告]
发表于 2013-05-29 18:03 |只看该作者
多谢指导,新手,不是很会用。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP