4412 使用usb摄像头拍照YUYV格式

一、内核设置

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 <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 CAMERA_DEVICE "/dev/video0"
#define CAPTURE_FILE "frame.jpg"

#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 failed\n", 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: %s\n", cap.driver);
    printf("*\tcard: %s\n", cap.card);
    printf("*\tbus_info: %s\n", cap.bus_info);
    printf("*\tversion: %08X\n", cap.version);
    printf("*\tcapabilities: %08X\n", 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: %d\n", fmt.type);
    printf("*\twidth: %d\n", fmt.fmt.pix.width);
    printf("*\theight: %d\n", fmt.fmt.pix.height);

    char fmtstr[8];
    memset(fmtstr, 0, 8);
    memcpy(fmtstr, &fmt.fmt.pix.pixelformat, 4);
    printf("*\tpixelformat: %s\n", fmtstr);
    printf("*\tfield: %d\n", fmt.fmt.pix.field);
    printf("*\tbytesperline: %d\n", fmt.fmt.pix.bytesperline);
    printf("*\tsizeimage: %d\n", fmt.fmt.pix.sizeimage);
    printf("*\tcolorspace: %d\n", fmt.fmt.pix.colorspace);
    printf("*\tpriv: %d\n", fmt.fmt.pix.priv);
    //    printf("*\traw_data: %s\n", 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.%s\n", 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 memory\n");
        exit(EXIT_FAILURE);
    }    

    for(i=0;i<reqbuf.count;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: %s\n", 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=%d\n", 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 failed\n");
        return -1;
    }
    fwrite(buffers[buf.index].start, 1, buf.length, fp);
    fclose(fp);
    printf("Capture one frame saved in %s\n", 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;
}

三、使用软件打开

不过要选择对应的格式:

猜你喜欢

转载自www.cnblogs.com/ch122633/p/9821784.html