历史上的今天
返回首页

历史上的今天

今天是:2024年12月29日(星期日)

2021年12月29日 | 4412 使用usb摄像头拍照YUYV格式

2021-12-29 来源:eefocus

一、内核设置

Linux内核中已经带有很完善的USB摄像头驱动,支持几乎所有的USB摄像头,我们只需要配置内核,选择上相应的Sensor型号即可。


配置内核,支持USB摄像头:


    Device Drivers --->

        <*> Multimedia support --->

            <*> Video For Linux

            [*] Enable Video For Linux API 1 (DEPRECATED)

            [*] Video capture adapters --->

                [*] V4L USB devices --->

                    <*> USB Video Class (UVC)

                    [*] UVC input events device support

                    [*] GSPCA based webcams --->


到这里,我们就可以选择所需要的USB摄像头驱动,当然也可以选择所有的USB摄像头驱动支持(这样编译出的内核会比较大)

GSPCA是一个万能摄像头驱动程序,进入GSPCA based webcams进行选择。

 

插入USB摄像头(我使用的UVC摄像头),会提示:

usb 1-1.1: new full speed USB device using s3c2410-ohci and address 3

usb 1-1.1: New USB device found, idVendor=0ac8, idProduct=3450

usb 1-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0

usb 1-1.1: Product: Deasy USB2.0 Camera

usb 1-1.1: Manufacturer: Vimicro Corp.

uvcvideo: Found UVC 1.00 device Deasy USB2.0 Camera (0ac8:3450)

input: Deasy USB2.0 Camera as 

/devices/platform/s3c2410-ohci/usb1/1-1/1-1.1/1-1.1:1.0/input/input3

 

它的设备名称是:/dev/video0

USB摄像头一般都是基于V4L2架构的,需要编写V4L2架构的程序来操作摄像头


二、编写V4L2的应用程序


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include


#include

#include


#define CAMERA_DEVICE "/dev/video0"

#define CAPTURE_FILE "frame.jpg?imageView2/2/w/550"


#define VIDEO_WIDTH  640

#define VIDEO_HEIGHT 480

#define VIDEO_FORMAT V4L2_PIX_FMT_YUYV

#define BUFFER_COUNT 4


typedef struct VideoBuffer {

    void *start;

    size_t length;

}VideoBuffer;


int fd;             //摄像头文件描述符


void open_camera(char *path);

void get_camera_info();

void get_vedio_info();


//打开设备

void open_camera(char *path)

{

    fd = open(CAMERA_DEVICE, O_RDWR, 0);

    if(fd < 0) {

        printf("Open %s failedn", CAMERA_DEVICE);

        exit(EXIT_FAILURE);

    }

}


//获取驱动信息

void get_camera_info()

{

    struct v4l2_capability cap;

    ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);

    if(ret < 0) {

        printf("VIDIOC_QUERYCAP failed (%d)n", ret);

        return ret;

    }

    // Print capability informations

    printf("Capbility Informations:n");

    printf("*tdriver: %sn", cap.driver);

    printf("*tcard: %sn", cap.card);

    printf("*tbus_info: %sn", cap.bus_info);

    printf("*tversion: %08Xn", cap.version);

    printf("*tcapabilities: %08Xn", cap.capabilities);

}


//获取视频格式

void get_vedio_info()

{

    struct v4l2_format fmt;

    memset(&fmt, 0, sizeof(fmt));

    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    ret = ioctl(fd, VIDIOC_G_FMT, &fmt);

    if(ret < 0) {

        printf("VIDIOC_G_FMT failed (%d)n", ret);

        return ret;

    }

    // Print Stream Format

    printf("Stream Format Informations:n");

    printf("*ttype: %dn", fmt.type);

    printf("*twidth: %dn", fmt.fmt.pix.width);

    printf("*theight: %dn", fmt.fmt.pix.height);


    char fmtstr[8];

    memset(fmtstr, 0, 8);

    memcpy(fmtstr, &fmt.fmt.pix.pixelformat, 4);

    printf("*tpixelformat: %sn", fmtstr);

    printf("*tfield: %dn", fmt.fmt.pix.field);

    printf("*tbytesperline: %dn", fmt.fmt.pix.bytesperline);

    printf("*tsizeimage: %dn", fmt.fmt.pix.sizeimage);

    printf("*tcolorspace: %dn", fmt.fmt.pix.colorspace);

    printf("*tpriv: %dn", fmt.fmt.pix.priv);

    //    printf("*traw_data: %sn", fmt.fmt.raw_data);


    /* 显示所有支持的格式 */

    struct v4l2_fmtdesc fmtdesc;

    fmtdesc.index = 0;

    fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    printf("Support format:n");

    while(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != -1) {

        printf("t%d.%sn", fmtdesc.index+1, fmtdesc.description);

        fmtdesc.index++;

    }

}


int main()

{

    int i, ret;

    open_camera(CAMERA_DEVICE);

    

    get_camera_info();

    

    get_vedio_info();


    //请求分配内存

    struct v4l2_requestbuffers reqbuf;

    reqbuf.count = BUFFER_COUNT;

    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    reqbuf.memory = V4L2_MEMORY_MMAP;

    ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf);

    if(ret < 0) {

        printf("VIDIOC_REQBUFS failed (%d)n", ret);

        return ret;

    }

    //获取空间

    VideoBuffer *buffers = calloc(reqbuf.count, sizeof(*buffers));

    if(!buffers) {

        //映射

        fprintf(stderr, "Out of memoryn");

        exit(EXIT_FAILURE);

    }    


    for(i=0;i        struct v4l2_buffer buf;

        memset(&buf, 0, sizeof(buf));

        buf.index = i;

        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

        buf.memory = V4L2_MEMORY_MMAP;

        ret = ioctl(fd, VIDIOC_QUERYBUF, &buf);

        if(ret < 0) {

            printf("VIDIOC_QUERYBUF (%d) failed (%d)n", i, ret);

            return ret;

        }

        // mmap buffer

        buffers[i].length = buf.length;

        buffers[i].start = (char *)mmap(0, buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, 

            fd, buf.m.offset);

        if(buffers[i].start == MAP_FAILED) {

            printf("mmap (%d) failed: %sn", i, strerror(errno));

            return -1;

        }


        // Queen buffer

        ret = ioctl(fd, VIDIOC_QBUF, &buf);

        if(ret < 0) {

            printf("VIDIOC_QBUF (%d) failed (%d)n", i, ret);

            return -1;

        }


        printf("Frame buffer: %d: address=0x%x, length=%dn", i,

            (unsigned int)buffers[i].start, buffers[i].length);

    }


    // 开始录制

    struct v4l2_buffer buf;

    enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    buf.index = 0;

    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    buf.memory = V4L2_MEMORY_MMAP;

    ret = ioctl(fd, VIDIOC_STREAMON, &type);

    if (ret < 0) {

        printf("VIDIOC_STREAMON failed (%d)n", ret);

        return ret;

    }


    // Get frame

    ret = ioctl(fd, VIDIOC_DQBUF, &buf);

    if (ret < 0) {

        printf("VIDIOC_DQBUF failed (%d)n", ret);

        return ret;

    }


    // Process the frame

    FILE *fp = fopen(CAPTURE_FILE, "wb");

    if (fp < 0) {

        printf("open frame data file failedn");

        return -1;

    }

    fwrite(buffers[buf.index].start, 1, buf.length, fp);

    fclose(fp);

    printf("Capture one frame saved in %sn", CAPTURE_FILE);


    // Re-queen buffer

    ret = ioctl(fd, VIDIOC_QBUF, &buf);

    if (ret < 0) {

        printf("VIDIOC_QBUF failed (%d)n", ret);

        return ret;

    }


    // Release the resource

    for(i=0;i<4;i++) {

        munmap(buffers[i].start, buffers[i].length);

    }


    close(fd);

    printf("Camera test Done.n");

    return 0;

}


三、使用软件打开

不过要选择对应的格式:


推荐阅读

史海拾趣

Dean Technology公司的发展小趣事

Dean Technology公司起源于上世纪80年代,当时电子行业正经历着飞速的发展。创始人凭借其深厚的电子技术背景和敏锐的市场洞察力,决定进入高压二极管领域。他带领研发团队不断攻克技术难题,成功推出了一系列性能稳定、品质可靠的高压二极管产品,奠定了公司在行业中的技术领先地位。

北京人民电器厂公司的发展小趣事

为了加强技术研发和创新能力,北京人民电器建立了北京市级技术研究中心,并吸引了教授级高工、博士后、博士、硕士等多层次的专业技术人才。这些人才为公司的新产品研发、技术创新提供了强大的智力支持,使得北京人民电器在激烈的市场竞争中始终保持领先地位。

ALD [Advanced Linear Devices]公司的发展小趣事

为了加强技术研发和创新能力,北京人民电器建立了北京市级技术研究中心,并吸引了教授级高工、博士后、博士、硕士等多层次的专业技术人才。这些人才为公司的新产品研发、技术创新提供了强大的智力支持,使得北京人民电器在激烈的市场竞争中始终保持领先地位。

Heraeus公司的发展小趣事

北京人民电器厂有限公司,作为北方地区最大的低压电器制造企业,于1995年成功研发出全球首台高分断微型直流断路器。这一创新成果不仅填补了国内空白,更在国际上展现了中国在低压电器领域的研发实力。该断路器的诞生,标志着北京人民电器在直流断路器技术领域迈出了坚实的一步,为后续的产品研发和市场拓展奠定了坚实的基础。

Boundary Devices公司的发展小趣事

Boundary Devices公司成立于2003年,总部位于美国亚利桑那州。创立之初,公司便专注于嵌入式系统硬件的开发与生产,凭借对技术的深刻理解和市场需求的敏锐洞察,Boundary Devices迅速在行业中崭露头角。其推出的Boundary Devices插座和适配器,因其兼容性强、性能稳定而备受市场青睐。同时,公司与NXP/Freescale建立了紧密的合作关系,共同推进i.MX系列处理器的应用与发展,为公司的后续发展奠定了坚实的基础。

Alliance Memory公司的发展小趣事

作为一家有社会责任感的企业,Boundary Devices始终关注环境保护和可持续发展。公司在生产过程中积极采用环保材料和技术,减少对环境的影响。同时,公司还积极参与社会公益活动,为社会的发展贡献自己的力量。这些举措不仅提升了公司的社会形象,也为公司的长期发展奠定了坚实的基础。

以上五个故事基于Boundary Devices公司的发展背景和电子行业的一般趋势进行创作,旨在展示该公司在不同阶段的成长与发展。然而,实际的公司发展历程可能更加复杂和丰富,需要更多的资料和信息来深入了解。

问答坊 | AI 解惑

夏玄雪(我喜欢的一本书,推荐你看)

我喜欢的一本书,推荐你看 呵呵…

查看全部问答>

疯狂的ISE软件,崩溃了

搞了一段时间ISE,几乎就要崩溃了     最近做个东西,要用到xilinx的ISe开发软件,找了很久,也下载了几个 但都是没法安装,把我搞惨了,哪位朋友能给我发一个不?版本不要太高, ise6.2等级别的,万分感谢了 我的邮箱是317930100@qq ...…

查看全部问答>

啥地方要用到30层PCB?

来自EEWORLD合作群:arm linux fpga 嵌入0(49900581) 群主:wangkj…

查看全部问答>

LED芯片发光简点介绍

LED是T型和N型半导体,三价有电洞,五价提供电子,两者结合中间有空乏区,能够产生能量,光就发出来。由于它是半导体,有能隙,随著参杂元素的不同而产生不同能隙,从氮化镓的3.4eV到磷化铟的1.35eV,波长亦随著改变,而产生出不同的颜色,从紫外光 ...…

查看全部问答>

求菲利浦的 PDIUSBD12 的驱动,和使用方法

用51 + PDIUSBD12 ,实现和 PC通信,固件程序写好了,可是找不到PC winxp的驱动, 求菲利浦的 PDIUSBD12 的驱动,和使用方法。 如果谁知道哪里可以下载麻烦告知一下。也可发我邮箱 yuexianhanshu@yahoo.com.cn 谢了…

查看全部问答>

如何支持media player?

wince5.0,已经把media player相关的组件都加入了,格式支持都加入了,基本上multimedia里面的都加上了。 启动后看到.mpg,.wmv的文件图标改了,.avi的图标没变。 打开.wmv,提示缺少一个解码器,然后只有声音没有图像。 .mpg的都不能打开。试过 ...…

查看全部问答>

用89C2051芯片取代89c51芯片的问题

本人用了89C51写了一个时钟显示程序,硬件电路共有4个单独的数码管显示,P1.1G至P1.7接了数码管的A、B、C、D、E、F、G   P2.3接了显示时的个位数码管DP脚,P2.7、P2.6、P2.5、P2.4分别接了时的十位数码管、时的个位数码管、分的十位数码管、 ...…

查看全部问答>

智能家居系统中国标准

基于EIB标准的智能家居系统,供大家参考…

查看全部问答>

STM32的引脚配置确实灵活!

                                 灵活到让人有点不知所措了!…

查看全部问答>