linux 使用标准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>
#include <time.h>
#include <strings.h>

#define DEFAULT_WIDTH    640
#define DEFAULT_HEIGHT    480
#define DEFAULT_BUFFER_COUNT 4
#define TEST_COUNT    20


void get_info(int fd)
{

 
    printf("【**********************所有支持的格式及分辨率:****************************】\n");
    enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    struct v4l2_fmtdesc fmt_1;
    struct v4l2_frmsizeenum frmsize;
    struct v4l2_frmivalenum frmival;

    fmt_1.index = 0;
    fmt_1.type = type;
    while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt_1) >= 0) {


    printf("%d.%s\n",fmt_1.index+1,fmt_1.description);


    frmsize.pixel_format = fmt_1.pixelformat;

    frmsize.index = 0;

    while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) >= 0){

    if(frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE){
    printf("\t%d.%dx%d\n",frmsize.index+1,frmsize.discrete.width, frmsize.discrete.height);
    }
    frmsize.index++;
    }

    fmt_1.index++;
    }

    printf("\n");


    printf("【***********************获取帧率信息**************************】\n");
    
    struct v4l2_streamparm Stream_Parm;

    Stream_Parm.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

    if(ioctl(fd,VIDIOC_G_PARM,&Stream_Parm)==-1)

    {

    perror("ioctl");

    exit(EXIT_FAILURE);

    }

    printf("Frame rate: %u/%u\n",
    Stream_Parm.parm.capture.timeperframe.numerator,
    Stream_Parm.parm.capture.timeperframe.denominator);

    printf("\n");

}


void set_format(int fd)
{
    printf("【***********************设置默认配置**************************>】\n");
    struct v4l2_format fmt;

    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
    fmt.fmt.pix.width = DEFAULT_WIDTH; //宽度
    fmt.fmt.pix.height =DEFAULT_HEIGHT; //高度
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; //像素格式
                // V4L2_PIX_FMT_YUYV
    fmt.fmt.pix.field = V4L2_FIELD_ANY;
    

    if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0)
    {
    printf("set format error\n");
    close(fd);
    exit(0);
    }
    
    printf("set defualt format successfuly\n");

    if(ioctl(fd,VIDIOC_G_FMT,&fmt)<0)
    {
    printf("get format error\n");
    close(fd);
    exit(0);
    }

    printf("Current format:\n");
    if(fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG )
    {
    printf("MJPEG:");
    }
    else if(fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
    {
    printf("YUYV:");
    }
    else 
    printf("unknown format:");
    
    printf("%dx%d\n",fmt.fmt.pix.width,fmt.fmt.pix.height);


}

unsigned char * bufs[DEFAULT_BUFFER_COUNT]={0};


int i=0;
void unmap(int length)
{
    int a ; 
    for(a=0;a< i ; a++)
    munmap(bufs[i],length);
    ;
}

void video_test(int fd)
{

    printf("【***********************测试**************************>】\n");
    printf("共拍摄%d张图片\n",TEST_COUNT);    
    printf("一轮拍摄%d张图片\n",DEFAULT_BUFFER_COUNT);

    int test_count = TEST_COUNT-DEFAULT_BUFFER_COUNT;
    
    static int again =0;
    struct v4l2_requestbuffers req;
        req.count               = DEFAULT_BUFFER_COUNT;
        req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        req.memory              = V4L2_MEMORY_MMAP;
    

    if(!again)
    {
        //申请缓冲,count是申请的数量
    if(ioctl (fd, VIDIOC_REQBUFS, &req) < 0)
    {
    printf("failture VIDIOC_REQBUFS\n");
    close(fd);
    exit(0);
    }

    if (req.count < 2)
    {    
    printf("req bufs error \n");
    exit(-1);
    }

    }

        int len ;


        for (i = 0; i < req.count;i++)
             {

        struct v4l2_buffer buf;
               bzero(&buf,sizeof(buf));
        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
               buf.memory      = V4L2_MEMORY_MMAP;
               buf.index       = i ; 
 
               if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buf)) //映射用户空间
                  {
                printf ("VIDIOC_QUERYBUF error\n");
                close(fd);
        exit(0);
                  }

                      bufs[i]             = mmap (NULL ,    
                                        buf.length,
                                        PROT_READ ,
                                        MAP_SHARED ,
                                        fd,
                                        buf.m.offset);
 
              if (MAP_FAILED == bufs[i])
                 {
                   printf ("mmap failed\n");
                   goto err;
                 }

        len=buf.length;

                 }

        /*注意是先开启再QBUF*/
        int on ; 
        on=V4L2_BUF_TYPE_VIDEO_CAPTURE;
            if(ioctl(fd,VIDIOC_STREAMON,&on)<0)
            {
            perror("on");
            return;
            }

        clock_t start,end;

        int a =0;

        FILE * fl=NULL;


        fl=fopen("./test.jpg","w+");

        start=clock();


        while(test_count >0)
        {
        for(a=0;a<req.count;a++)
        {


        struct v4l2_buffer buf;
               bzero(&buf,sizeof(buf));
        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
               buf.memory      = V4L2_MEMORY_MMAP;
        buf.index    = a;

        if(ioctl(fd,VIDIOC_QBUF,&buf)<0)
            {
            printf("QBUF error\n");
        goto err ; 
        }    
        }

        for(a=0;a<req.count;a++)
        {

        struct v4l2_buffer dbuf;
               bzero(&dbuf,sizeof(dbuf));
        dbuf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
               dbuf.memory      = V4L2_MEMORY_MMAP;


        if(ioctl(fd,VIDIOC_DQBUF,&dbuf)<0)
            {
            printf("DQBUF error \n");
        goto err ; 
        }

        fwrite(bufs[a],1,dbuf.bytesused,fl);
            fflush(fl);

        }        
        
        printf("test_count = %d\n",test_count);
        test_count  -=req.count;
        
        }


        end=clock();


        fclose(fl);

        unmap(len);

        double seconds  =(double)(end - start)/CLOCKS_PER_SEC;
        printf("end \n");
        printf("use time %1.8f\n",seconds);
        
        again= 1 ;

        return ;
err:
        unmap(len);
        close(fd);
        exit(0);

}


void main(int argc ,char * argv[])
{
    if(argc != 2)
    {
    printf("usage: video_test /dev/video0\n");
    exit(0);
    }


    int fd = open(argv[1],O_RDWR);

    if(fd < 0)
    {
    printf("open video device  error\n");
    exit(0);
    }
    
    char select[30] = {0};
    int result = 0;
retry:
    printf("Welcome to video test\n");
    printf("select:\n");
    printf("1.get video message\n");
    printf("2.set video message\n");
    printf("3.video_test\n");
    printf("4.exit\n");

    printf("your select:");

    scanf("%s",select);

    result = strlen(select);
    if(result != 1)
    goto retry ;

    if(select[0] > '4' || select[0] < '1')
    goto retry ;

    switch(select[0])
    {
        case '1':get_info(fd);
            break;
        case '2':
             set_format(fd);
            break;
        case '3':
             video_test(fd);
            break;
        case '4':
            close(fd);
            
            exit(0);
            
            break;
    }

    

    goto retry ; 


}
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值