Linux驱动V4L2摄像头

一、内容简介

没玩过摄像头,做项目需要在网上找了好长时间没有很合适的,经过自己修改最终实现了摄像头传视频!其实传视频的原理就是一帧一帧的传图片,所以需要获取图片的内容信息和内容长度的信息。再此设置了两个接口,定义了两个变量供主函数调用。

二、camera.c

#include "camera.h"


typedef struct VideoBuffer {
    void   *start;
    size_t  length;
} VideoBuffer;


int cam_len;
char cam_buf[500*1024] = {\0};

sem_t rt, dt;//定义两个信号量


int camera()
{

    int i, ret;

    // 打开设备
    int fd;

    fd = open(CAMERA_DEVICE, O_RDWR, 0);
    if (fd < 0) {
        printf("Open %s failed\n", CAMERA_DEVICE);
        return -1;
    }

    // 获取驱动信息
    struct v4l2_capability cap;
    ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
    if (ret < 0) {
        printf("VIDIOC_QUERYCAP failed (%d)\n", ret);
        return ret;
    }
    // Print capability infomations
    printf("Capability Informations:\n");
    printf(" driver: %s\n", cap.driver);
    printf(" card: %s\n", cap.card);
    printf(" bus_info: %s\n", cap.bus_info);
    printf(" version: X\n", cap.version);
    printf(" capabilities: X\n", cap.capabilities);

    // 设置视频格式
    struct v4l2_format fmt;
    memset(&fmt, 0, sizeof(fmt));
    fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width       = VIDEO_WIDTH;
    fmt.fmt.pix.height      = VIDEO_HEIGHT;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;//设置视频采集格式
    fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
    ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
    if (ret < 0) {
        printf("VIDIOC_S_FMT failed (%d)\n", ret);
        return ret;
    }


    // 获取视频格式
    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(" type: %d\n", fmt.type);
    printf(" width: %d\n", fmt.fmt.pix.width);
    printf(" height: %d\n", fmt.fmt.pix.height);
    char fmtstr[8];
    memset(fmtstr, 0, 8);
    memcpy(fmtstr, &fmt.fmt.pix.pixelformat, 4);
    printf(" pixelformat: %s\n", fmtstr);
    printf(" field: %d\n", fmt.fmt.pix.field);
    printf(" bytesperline: %d\n", fmt.fmt.pix.bytesperline);
    printf(" sizeimage: %d\n", fmt.fmt.pix.sizeimage);
    printf(" colorspace: %d\n", fmt.fmt.pix.colorspace);
    printf(" priv: %d\n", fmt.fmt.pix.priv);
    printf(" raw_date: %s\n", fmt.fmt.raw_data);


    //调节显示.
    struct v4l2_control  ctrl;
    
    ctrl.id = V4L2_CID_EXPOSURE_AUTO;
    ret = ioctl(fd, VIDIOC_G_CTRL, &ctrl);



    // 请求分配内存
    struct v4l2_requestbuffers reqbuf;

    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    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) );
    struct v4l2_buffer buf;


    for (i = 0; i < reqbuf.count; i++) 
    {
        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);
    }


    // 开始录制
    enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(fd, VIDIOC_STREAMON, &type);
    if (ret < 0) {
        printf("VIDIOC_STREAMON failed (%d)\n", ret);
        return ret;
    }




    while(1){

        //读取缓存、、读取一帧图片信息存到cam_len、cam_buf
        ret = ioctl(fd, VIDIOC_DQBUF, &buf);
        if (ret < 0) {
            printf("VIDIOC_DQBUF failed (%d)\n", ret);
            return ret;
        }
    //sem_wait(&rt);//线程同步,先获取一帧再发一帧
        cam_len = buf.length;
        memcpy(cam_buf,buffers[buf.index].start,buf.length);//内容为二进所以需要memcpy函数
    //sem_post(&dt);//线程同步

        //释放缓存
        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;
}

三、camera.h

#ifndef _CAMERA_H
#define _CAMERA_H

#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>

#include <pthread.h>

#include <semaphore.h>

#define CAMERA_DEVICE "/dev/video0"
#define CAPTURE_FILE "QY.jpg"

#define VIDEO_WIDTH 640
#define VIDEO_HEIGHT 480
#define VIDEO_FORMAT V4L2_PIX_FMT_YUYV
#define BUFFER_COUNT 4


extern int cam_len;
extern char cam_buf[500*1024];

extern sem_t rt;//定义两个信号量
extern sem_t dt;
int camera();



#endif

 

Linux驱动V4L2摄像头

上一篇:es在win下添加数据(二)


下一篇:Linux 系统下挂载linux 系统盘