Tegra(ubuntu)调用摄像头V4L2,并用YUV转RGB

来源:互联网 发布:克克mp3录音软件 编辑:程序博客网 时间:2024/06/06 07:52

首先检查摄像头是否可用,按步骤装好luvcview并测试

地址:http://developer.t-firefly.com/thread-957-1-1.html

一般的摄像头支持JPEG和YUV,有专门函数测试是否支持RGB的。如果支持就能省去YUV到RGB的步骤了。

然后新建capture_mmap.c

#include "captrue_mmap.h"
static int WIDTH = 640;
static int HEIGHT = 360;
static   void  open_device( void ) {
    struct  stat st;
    if  (-1 == stat(dev_name, &st)) {
        fprintf(stderr, "Cannot identify '%s': %d, %s\n" , dev_name, errno,
                strerror(errno));
        exit(EXIT_FAILURE);
    }
    if  (!S_ISCHR(st.st_mode)) {
        fprintf(stderr, "%s is no device\n" , dev_name);
        exit(EXIT_FAILURE);
    }
    fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
    if  (-1 == fd) {
        fprintf(stderr, "Cannot open '%s': %d, %s\n" , dev_name, errno,
                strerror(errno));
        exit(EXIT_FAILURE);
    }
}
static   void  init_device( void ) {
    struct  v4l2_capability cap;
    struct  v4l2_cropcap cropcap;
    struct  v4l2_crop crop;
    struct  v4l2_format fmt;
    unsigned int  min;
    if  (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap))   {
        if  (EINVAL == errno)
       {
            fprintf(stderr, "%s is no V4L2 device\n" , dev_name);
            exit(EXIT_FAILURE);
        }
        else
       {
            errno_exit("VIDIOC_QUERYCAP" );
        }
    }
    if  (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
   {
        fprintf(stderr, "%s is no video capture device\n" , dev_name);
        exit(EXIT_FAILURE);
    }
    if  (!(cap.capabilities & V4L2_CAP_STREAMING))
   {
            fprintf(stderr, "%s does not support streaming i/o\n" , dev_name);
            exit(EXIT_FAILURE);
    }
    //////not all capture support crop!!!!!!!
    /* Select video input, video standard and tune here. */
    printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-\n" );
    CLEAR (cropcap);
    cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if  (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
#ifndef CROP_BY_JACK
        crop.c = cropcap.defrect; /* reset to default */
#else
        crop.c.left = cropcap.defrect.left;
        crop.c.top = cropcap.defrect.top;
        crop.c.width = 480;
        crop.c.height = 320;
#endif
        printf("----->has ability to crop!!\n" );
        printf("cropcap.defrect = (%d, %d, %d, %d)\n" , cropcap.defrect.left,
                cropcap.defrect.top, cropcap.defrect.width,
                cropcap.defrect.height);
        if  (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
            switch  (errno) {
            case  EINVAL:
                /* Cropping not supported. */
                break ;
            default :
                /* Errors ignored. */
                break ;
            }
            printf("-----!!but crop to (%d, %d, %d, %d) Failed!!\n" ,
                    crop.c.left, crop.c.top, crop.c.width, crop.c.height);
        } else  {
            printf("----->sussess crop to (%d, %d, %d, %d)\n" , crop.c.left,
                    crop.c.top, crop.c.width, crop.c.height);
        }
    } else  {
        /* Errors ignored. */
        printf("!! has no ability to crop!!\n" );
    }
    printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-\n" );
    printf("/n" );
    ////////////crop finished!
    //////////set the format
    CLEAR (fmt);
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width = WIDTH;
    fmt.fmt.pix.height = HEIGHT;
    //V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV420 鈥?Planar formats with 1/2 horizontal and vertical chroma resolution, also known as YUV 4:2:0
    //V4L2_PIX_FMT_YUYV 鈥?Packed format with 1/2 horizontal chroma resolution, also known as YUV 4:2:2
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_YUV420;//V4L2_PIX_FMT_YUYV;
    fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
    {
        printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-\n" );
        printf("=====will set fmt to (%d, %d)--" , fmt.fmt.pix.width,
                fmt.fmt.pix.height);
        if  (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {
            printf("V4L2_PIX_FMT_YUYV\n" );
        } else   if  (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
            printf("V4L2_PIX_FMT_YUV420\n" );
        } else   if  (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) {
            printf("V4L2_PIX_FMT_NV12\n" );
        }
    }
    if  (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
        errno_exit("VIDIOC_S_FMT" );
    {
        printf("=====after set fmt\n" );
        printf("    fmt.fmt.pix.width = %d\n" , fmt.fmt.pix.width);
        printf("    fmt.fmt.pix.height = %d\n" , fmt.fmt.pix.height);
        printf("    fmt.fmt.pix.sizeimage = %d\n" , fmt.fmt.pix.sizeimage);
        cap_image_size = fmt.fmt.pix.sizeimage;
        printf("    fmt.fmt.pix.bytesperline = %d\n" , fmt.fmt.pix.bytesperline);
        printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-\n" );
        printf("/n" );
    }
    cap_image_size = fmt.fmt.pix.sizeimage;
    /* Note VIDIOC_S_FMT may change width and height. */
    printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-\n" );
    /* Buggy driver paranoia. */
    min = fmt.fmt.pix.width * 2;
    if  (fmt.fmt.pix.bytesperline < min)
        fmt.fmt.pix.bytesperline = min;
    min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
    if  (fmt.fmt.pix.sizeimage < min)
        fmt.fmt.pix.sizeimage = min;
    printf("After Buggy driver paranoia\n" );
    printf("    >>fmt.fmt.pix.sizeimage = %d\n" , fmt.fmt.pix.sizeimage);
    printf("    >>fmt.fmt.pix.bytesperline = %d\n" , fmt.fmt.pix.bytesperline);
    printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-\n" );
    printf("\n" );
    init_mmap();
}
static   void  init_mmap( void )
{
    struct  v4l2_requestbuffers req;
    CLEAR (req);
    req.count = 4;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    if  (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
        if  (EINVAL == errno) {
            fprintf(stderr, "%s does not support "
                "memory mapping\n" , dev_name);
            exit(EXIT_FAILURE);
        } else  {
            errno_exit("VIDIOC_REQBUFS" );
        }
    }
    if  (req.count < 2) {
        fprintf(stderr, "Insufficient buffer memory on %s\n" , dev_name);
        exit(EXIT_FAILURE);
    }
    buffers = calloc(req.count, sizeof (*buffers));
    if  (!buffers) {
        fprintf(stderr, "Out of memory\n" );
        exit(EXIT_FAILURE);
    }
    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;
        if  (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
            errno_exit("VIDIOC_QUERYBUF" );
        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);
        if  (MAP_FAILED == buffers[n_buffers].start)
            errno_exit("mmap" );
    }
}
static   void  start_capturing( void ) {
    unsigned int  i;
    enum  v4l2_buf_type type;
    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 == xioctl(fd, VIDIOC_QBUF, &buf))
                errno_exit("VIDIOC_QBUF" );
        }
     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     if  (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
            errno_exit("VIDIOC_STREAMON" );
}
static   void  mainloop( void )
 {
    unsigned int  count;
    count = 100;
    while  (count-- > 0)
    {
        for  (;;)
        {
            if  (read_frame())
                break ;
            /* EAGAIN - continue select loop. */
        }
    }
}
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;
        if  (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
            switch  (errno) {
            case  EAGAIN:
                return  0;
            case  EIO:
                /* Could ignore EIO, see spec. */
                /* fall through */
            default :
                errno_exit("VIDIOC_DQBUF" );
            }
        }
        assert(buf.index < n_buffers);
        //      printf("length = %d/r", buffers[buf.index].length);
        //      process_image(buffers[buf.index].start, buffers[buf.index].length);
        printf("image_size = %d,\t IO_METHOD_MMAP buffer.length=%d\r" ,
                cap_image_size, buffers[0].length);
        process_image(buffers[0].start, cap_image_size);
        if  (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
            errno_exit("VIDIOC_QBUF" );
    return  1;
}
static void yuyv_to_rgb(unsigned char * yuv)
{
    unsigned char* rgb = (unsigned char*) malloc(WIDTH * HEIGHT * 3);
    unsigned char* result = rgb;
    unsigned int i;
    unsigned char* y0 = yuv + 0;
    unsigned char* u0 = yuv + 1;
    unsigned char* y1 = yuv + 2;
    unsigned char* v0 = yuv + 3;
    unsigned  char* r0 = rgb + 0;
    unsigned  char* g0 = rgb + 1;
    unsigned  char* b0 = rgb + 2;
    unsigned  char* r1 = rgb + 3;
    unsigned  char* g1 = rgb + 4;
    unsigned  char* b1 = rgb + 5;
    float rt0 = 0, gt0 = 0, bt0 = 0, rt1 = 0, gt1 = 0, bt1 = 0;
    int total = (WIDTH * HEIGHT) / 2;
    for(i = 0; i <= total ;i++)
    {
        bt0 = 1.164 * (*y0 - 16) + 2.018 * (*u0 - 128);
        gt0 = 1.164 * (*y0 - 16) - 0.813 * (*v0 - 128) - 0.394 * (*u0 - 128);
        rt0 = 1.164 * (*y0 - 16) + 1.596 * (*v0 - 128);
    bt1 = 1.164 * (*y1 - 16) + 2.018 * (*u0 - 128);
        gt1 = 1.164 * (*y1 - 16) - 0.813 * (*v0 - 128) - 0.394 * (*u0 - 128);
        rt1 = 1.164 * (*y1 - 16) + 1.596 * (*v0 - 128);
       if(rt0 > 250)  rt0 = 255;
if(rt0 < 0)    rt0 = 0;
if(gt0 > 250) gt0 = 255;
if(gt0 < 0)gt0 = 0;
if(bt0 > 250)bt0 = 255;
if(bt0 < 0)bt0 = 0;
if(rt1 > 250)rt1 = 255;
if(rt1 < 0)rt1 = 0;
if(gt1 > 250)gt1 = 255;
if(gt1 < 0)gt1 = 0;
if(bt1 > 250)bt1 = 255;
if(bt1 < 0)bt1 = 0;
*r0 = (unsigned char)rt0;
*g0 = (unsigned char)gt0;
*b0 = (unsigned char)bt0;
*r1 = (unsigned char)rt1;
*g1 = (unsigned char)gt1;
*b1 = (unsigned char)bt1;
        yuv = yuv + 4;
        rgb = rgb + 6;
        if(yuv == NULL)
          break;
        y0 = yuv;
        u0 = yuv + 1;
        y1 = yuv + 2;
        v0 = yuv + 3;
        r0 = rgb + 0;
        g0 = rgb + 1;
        b0 = rgb + 2;
        r1 = rgb + 3;
        g1 = rgb + 4;
        b1 = rgb + 5;
    }
    unsigned char *damg = result;
    FILE *file = fopen("abc.txt","w+");
    if(file == NULL)
    {
        printf("file is null!\n");
        return;
    }
    for(i = 0;i<WIDTH * HEIGHT * 3;i++)
    {
        fprintf(file,"%d\t",*result);
        result++;
    }
    fclose(file);
}
static   void  process_image( const   void  * p,  int  len) {
    //  static char[115200] Outbuff ;
    fputc('.' , stdout);
    if  (len > 0) {
        fputc('.' , stdout);
        fwrite(p, 1, len, outf);
    }
    fflush(stdout);
    yuyv_to_rgb((unsigned char *)p);
}
static   void  errno_exit( const   char  * s) {
    fprintf(stderr, "%s error %d, %s\n" , s, errno, strerror(errno));
    exit(EXIT_FAILURE);
}
static   int  xioctl( int  fd,  int  request,  void  * arg) {
    int  r;
    do
        r = ioctl(fd, request, arg);
    while  (-1 == r && EINTR == errno);
    return  r;
}
static   void  stop_capturing( void ) {
    enum  v4l2_buf_type type;
        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        if  (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))
            errno_exit("VIDIOC_STREAMOFF" );
}
static   void  uninit_device( void ) {
    unsigned int  i;
        for  (i = 0; i < n_buffers; ++i)
            if  (-1 == munmap(buffers[i].start, buffers[i].length))
                errno_exit("munmap" );
    free(buffers);
}
static   void  close_device( void ) {
    if  (-1 == close(fd))
        errno_exit("close" );
    fd = -1;
}
int main()
{
    dev_name = "/dev/video0" ;
    outf = fopen("out.yuv" ,  "wb" );
    open_device();
    init_device();
    start_capturing();
    mainloop();
    printf("\n" );
    stop_capturing();
    fclose(outf);
    uninit_device();
    close_device();
    exit(EXIT_SUCCESS);
    return  0;
}

再建立capture_mmap.h文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h>             /* getopt_long() */
#include <fcntl.h>              /* low-level i/o */
#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>          /* for videodev2.h */
#include <linux/videodev2.h>
#define CLEAR(x) memset (&(x), 0, sizeof (x))
typedef   enum  {
    IO_METHOD_READ, IO_METHOD_MMAP, IO_METHOD_USERPTR,
} io_method;
struct  buffer {
    void  * start;
    size_t  length; //buffer's length is different from cap_image_size
};
static   char  * dev_name = NULL;
static  io_method io = IO_METHOD_MMAP; //IO_METHOD_READ;//IO_METHOD_MMAP;
static   int  fd = -1;
struct  buffer * buffers = NULL;
static  unsigned  int  n_buffers = 0;
static   FILE  * outf = 0;
static  unsigned  int  cap_image_size = 0; //to keep the real image size!!
static   void  open_device( void );
static   void  init_device( void );
static   void  init_mmap( void ) ;
static   void  start_capturing( void );
static   void  mainloop( void );
static   int  read_frame( void );
static   void  process_image( const   void  * p,  int  len);
static   void  errno_exit( const   char  * s);
static   int  xioctl( int  fd,  int  request,  void  * arg);
static   void  stop_capturing( void );
static   void  uninit_device( void );
static   void  close_device( void );

这样子得到的程序会有卡顿现象原因是建立了四个缓冲区

    req.count = 4;
但每次只取第一个,buffer[0],估计吧buffers[i].length与cap_image_size对比一下,应该就不会有卡顿现象了。

0 0
原创粉丝点击