摄像头应用编程(四):ARM Linux LCD实时预览UVC摄像头画面

[复制链接]
发表于 2025-10-22 03:00:17 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
1、媒介

本次应用步伐重要针对支持MJPEG格式输出的UVC摄像头。
源码可自行获取:https://github.com/Cohen0415/v4l2_app
2、环境先容

rk3566 + 7寸 mipi lcd + uvc摄像头
3、步调

应用步伐编写重要分为以下几个步调:
1、lcd初始化。
2、摄像头初始化。
3、摄像头收罗数据。
4、jpeg解码。
5、lcd表现。
4、应用步伐编写

4.1、lcd初始化

  1. typedef struct lcd_mes {
  2.     int fd;
  3.     unsigned char *fb_base;
  4.     int lcd_width;
  5.     int lcd_height;
  6.     unsigned int bpp;
  7.     unsigned int line_width;
  8. } lcd_mes;
  9. int lcd_init(const char *fb_dev, lcd_mes *lcd)
  10. {
  11.     int screen_size;
  12.     struct fb_var_screeninfo var;   
  13.     if (fb_dev == NULL)
  14.         goto _err;
  15.     /* 1. open /dev/fb* */   
  16.     lcd->fd = open(fb_dev, O_RDWR);
  17.     if(lcd->fd < 0)
  18.     {
  19.         printf("can not open %s\n", fb_dev);
  20.         goto _err;
  21.     }
  22.     /* 2. get lcd message */
  23.     if (ioctl(lcd->fd, FBIOGET_VSCREENINFO, &var))
  24.     {
  25.         printf("can not get var\n");
  26.         goto _err;
  27.     }
  28.     screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
  29.     lcd->line_width  = var.xres * var.bits_per_pixel / 8;
  30.     lcd->lcd_width = var.xres;
  31.     lcd->lcd_height = var.yres;
  32.     lcd->bpp = var.bits_per_pixel;
  33.     lcd->fb_base = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, lcd->fd, 0);
  34.     if (lcd->fb_base == (unsigned char *)-1)
  35.     {
  36.         printf("can not mmap\n");
  37.         goto _err;
  38.     }
  39.     memset(lcd->fb_base, 0x00, screen_size);
  40.     return 0;
  41. _err:
  42.     return -1;
  43. }
复制代码
4.2、摄像头初始化

使用v4l2接口初始化uvc摄像头:
  1. typedef struct camera_mes {
  2.     int fd;
  3.     void *bufs[32];
  4.     int bufs_index;
  5.     int buf_length;
  6.     char fmt[20];
  7.     int frame_x_size;
  8.     int frame_y_size;
  9. } camera_mes;
  10. int camera_init(const char *video, camera_mes *camera)
  11. {   
  12.     struct v4l2_fmtdesc fmtdesc;
  13.     struct v4l2_frmsizeenum fsenum;
  14.     int fmt_index = 0;
  15.     int frame_index = 0;
  16.     int buf_cnt;
  17.     int i;
  18.     if (video == NULL)
  19.         goto _err;
  20.     /* 1. open /dev/video* */
  21.     camera->fd = open(video, O_RDWR);
  22.     if (camera->fd < 0)
  23.     {
  24.         printf("can not open %s\n", video);
  25.         goto _err;
  26.     }
  27.     /* 2. query capability */
  28.     struct v4l2_capability cap;
  29.     memset(&cap, 0, sizeof(struct v4l2_capability));
  30.     if (0 == ioctl(camera->fd, VIDIOC_QUERYCAP, &cap))
  31.     {        
  32.         if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0)
  33.         {
  34.             fprintf(stderr, "Error opening device %s: video capture not supported.\n", video);
  35.             goto _ioc_querycap_err;
  36.         }
  37.         if(!(cap.capabilities & V4L2_CAP_STREAMING))
  38.         {
  39.             fprintf(stderr, "%s does not support streaming i/o\n", video);
  40.             goto _ioc_querycap_err;
  41.         }
  42.     }
  43.     else
  44.     {
  45.         printf("can not get capability\n");
  46.         goto _ioc_querycap_err;
  47.     }
  48.     /* 3. enum formt */
  49.     while (1)
  50.     {
  51.         fmtdesc.index = fmt_index;  
  52.         fmtdesc.type  = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  53.         if (0 != ioctl(camera->fd, VIDIOC_ENUM_FMT, &fmtdesc))
  54.             break;
  55.         frame_index = 0;
  56.         // printf("format %s,%d:\n", fmtdesc.description, fmtdesc.pixelformat);
  57.         while (1)
  58.         {
  59.             memset(&fsenum, 0, sizeof(struct v4l2_frmsizeenum));
  60.             fsenum.pixel_format = fmtdesc.pixelformat;
  61.             fsenum.index = frame_index;
  62.             /* get framesize */
  63.             if (ioctl(camera->fd, VIDIOC_ENUM_FRAMESIZES, &fsenum) == 0)
  64.             {
  65.                 // printf("\t%d: %d x %d\n", frame_index, fsenum.discrete.width, fsenum.discrete.height);
  66.             }
  67.             else
  68.             {
  69.                 break;
  70.             }
  71.             frame_index++;
  72.         }
  73.         fmt_index++;
  74.     }
  75.     /* 4. set formt */
  76.     struct v4l2_format fmt;
  77.     memset(&fmt, 0, sizeof(struct v4l2_format));
  78.     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  79.     fmt.fmt.pix.width = camera->frame_x_size;
  80.     fmt.fmt.pix.height = camera->frame_y_size;
  81.     fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
  82.     fmt.fmt.pix.field = V4L2_FIELD_ANY;
  83.     if (0 == ioctl(camera->fd, VIDIOC_S_FMT, &fmt))
  84.     {
  85.         // printf("the final frame-size has been set : %d x %d\n", fmt.fmt.pix.width, fmt.fmt.pix.height);
  86.         camera->frame_x_size = fmt.fmt.pix.width;
  87.         camera->frame_y_size = fmt.fmt.pix.height;
  88.         strncpy(camera->fmt, "Motion-JPEG", strlen("Motion-JPEG"));
  89.     }
  90.     else
  91.     {
  92.         printf("can not set format\n");
  93.         goto _ioc_sfmt_err;
  94.     }
  95.     /* 5. require buffer */
  96.     struct v4l2_requestbuffers rb;
  97.     memset(&rb, 0, sizeof(struct v4l2_requestbuffers));
  98.     rb.count = 32;
  99.     rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  100.     rb.memory = V4L2_MEMORY_MMAP;
  101.     if (0 == ioctl(camera->fd, VIDIOC_REQBUFS, &rb))
  102.     {
  103.         buf_cnt = rb.count;
  104.         for(i = 0; i < rb.count; i++)
  105.         {
  106.             struct v4l2_buffer buf;
  107.             memset(&buf, 0, sizeof(struct v4l2_buffer));
  108.             buf.index = i;
  109.             buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  110.             buf.memory = V4L2_MEMORY_MMAP;
  111.             if (0 == ioctl(camera->fd, VIDIOC_QUERYBUF, &buf))
  112.             {
  113.                 /* mmap */
  114.                 camera->bufs[i] = mmap(0, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, camera->fd, buf.m.offset);
  115.                 if(camera->bufs[i] == MAP_FAILED)
  116.                 {
  117.                     printf("Unable to map buffer");
  118.                     goto _err;
  119.                 }
  120.             }
  121.             else
  122.             {
  123.                 printf("can not query buffer\n");
  124.                 goto _err;
  125.             }            
  126.         }
  127.     }
  128.     else
  129.     {
  130.         printf("can not request buffers\n");
  131.         goto _ioc_reqbufs_err;
  132.     }
  133.     /* 6. queue buffer */
  134.     for(i = 0; i < buf_cnt; ++i)
  135.     {
  136.         struct v4l2_buffer buf;
  137.         memset(&buf, 0, sizeof(struct v4l2_buffer));
  138.         buf.index = i;
  139.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  140.         buf.memory = V4L2_MEMORY_MMAP;
  141.         if (0 != ioctl(camera->fd, VIDIOC_QBUF, &buf))
  142.         {
  143.             perror("Unable to queue buffer");
  144.             goto _ioc_qbuf_err;
  145.         }
  146.     }
  147.     camera->bufs_index = 0;     // init camera struct
  148.     camera->buf_length = 0;
  149.     return 0;
  150. _ioc_qbuf_err:
  151. _ioc_reqbufs_err:
  152. _ioc_sfmt_err:
  153. _ioc_querycap_err:
  154. _err:
  155.     return -1;
  156. }
复制代码
4.3、jpeg解码

  1. int jpeg_show_on_lcd(lcd_mes *lcd, camera_mes *camera)
  2. {
  3.     int min_width, min_height;
  4.     int valid_bytes;
  5.     int offset_x, offset_y;
  6.         struct jpeg_decompress_struct cinfo;
  7.         struct jpeg_error_mgr jerr;
  8.    
  9.         cinfo.err = jpeg_std_error(&jerr);      // 错误处理对象与解码对象绑定
  10.         jpeg_create_decompress(&cinfo);         // 初始化解码器
  11.         jpeg_mem_src(&cinfo, camera->bufs[camera->bufs_index], camera->buf_length);   // 指定JPEG数据的来源
  12.         jpeg_read_header(&cinfo, TRUE);         // 读取图像信息
  13.         cinfo.out_color_space = JCS_RGB;        // 设置解码后的颜色空间为RGB
  14.         jpeg_start_decompress(&cinfo);          // 开始解码
  15.        
  16.         unsigned char *jpeg_line_buf = (char *)malloc(cinfo.output_components * cinfo.output_width);    // 用于存储从JPEG解码器读取的一行数据
  17.         unsigned int *fb_line_buf = (int *)malloc(lcd->line_width);                                     // 用于存储转换后的RGB数据,准备写入framebuffer
  18.     min_width = (cinfo.output_width < lcd->lcd_width) ? cinfo.output_width : lcd->lcd_width;
  19.     min_height = (cinfo.output_height < lcd->lcd_height) ? cinfo.output_height : lcd->lcd_height;
  20.         valid_bytes = min_width * lcd->bpp / 8;             // 一行的有效字节数
  21.         unsigned char *ptr = lcd->fb_base;
  22.     offset_x = ((lcd->lcd_width - min_width) / 2) * lcd->bpp / 8;   // x方向居中
  23.     offset_y = (lcd->lcd_height - min_height) / 2;      // y方向居中
  24.     for (int i = 0; i < offset_y; i++)                  
  25.         ptr += lcd->lcd_width * lcd->bpp / 8;
  26.    
  27.     unsigned int red, green, blue;
  28.     unsigned int color;
  29.         while (cinfo.output_scanline < min_height)
  30.         {
  31.                 jpeg_read_scanlines(&cinfo, &jpeg_line_buf, 1); // 每次读取一行
  32.                 for(int i = 0; i < min_width; i++)              
  33.                 {
  34.                         red = jpeg_line_buf[i * 3];                 
  35.                         green = jpeg_line_buf[i * 3 + 1];           
  36.                         blue = jpeg_line_buf[i * 3 + 2];            
  37.                         color = red << 16 | green << 8 | blue;      // RGB888转RGB8888
  38.                         fb_line_buf[i] = color;
  39.                 }
  40.                 memcpy(ptr + offset_x, fb_line_buf, valid_bytes);   // 将一行数据写入framebuffer
  41.                 ptr += lcd->lcd_width * lcd->bpp / 8;               // 移动到下一行
  42.         }
  43.        
  44.         jpeg_finish_decompress(&cinfo);                     // 完成解码
  45.         jpeg_destroy_decompress(&cinfo);                    // 销毁解码对象
  46.         free(jpeg_line_buf);                                // 释放内存
  47.         free(fb_line_buf);                                  // 释放内存
  48.     return 0;
  49. }
复制代码
4.4、开启摄像头

  1. int main(int argc, char **argv)
  2. {
  3.     ...
  4.     /* start camera */
  5.     if (0 != ioctl(camera.fd, VIDIOC_STREAMON, &type))
  6.     {
  7.         printf("Unable to start capture\n");
  8.         goto _err;
  9.     }
  10.     printf("\nstart camera ...\n");
  11.     while (1)
  12.     {
  13.         /* poll */
  14.         memset(fds, 0, sizeof(fds));
  15.         fds[0].fd = camera.fd;
  16.         fds[0].events = POLLIN;
  17.         if (1 == poll(fds, 1, -1))
  18.         {
  19.             /* dequeue buffer */
  20.             struct v4l2_buffer buf;
  21.             memset(&buf, 0, sizeof(struct v4l2_buffer));
  22.             buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  23.             buf.memory = V4L2_MEMORY_MMAP;
  24.             
  25.             if (0 != ioctl(camera.fd, VIDIOC_DQBUF, &buf))
  26.             {
  27.                 printf("Unable to dequeue buffer\n");
  28.                 goto _ioc_dqbuf_err;
  29.             }
  30.             
  31.             /* jpeg show on lcd */
  32.             camera.bufs_index = buf.index;
  33.             camera.buf_length = buf.length;
  34.             jpeg_show_on_lcd(&lcd, &camera);
  35.             /* queue buffer */
  36.             if (0 != ioctl(camera.fd, VIDIOC_QBUF, &buf))
  37.             {
  38.                 printf("Unable to queue buffer");
  39.                 goto _ioc_qbuf_err;
  40.             }
  41.         }
  42.     }
  43.     ...
  44.    
  45. }
复制代码
4.5、完备的步伐如下

  1. #include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/ioctl.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <linux/types.h>          #include <linux/videodev2.h>#include <poll.h>#include <sys/mman.h>#include <jpeglib.h>#include <linux/fb.h>typedef struct lcd_mes {    int fd;    unsigned char *fb_base;    int lcd_width;    int lcd_height;    unsigned int bpp;    unsigned int line_width;} lcd_mes;typedef struct camera_mes {    int fd;    void *bufs[32];    int bufs_index;    int buf_length;    char fmt[20];    int frame_x_size;    int frame_y_size;} camera_mes;int jpeg_show_on_lcd(lcd_mes *lcd, camera_mes *camera)
  2. {
  3.     int min_width, min_height;
  4.     int valid_bytes;
  5.     int offset_x, offset_y;
  6.         struct jpeg_decompress_struct cinfo;
  7.         struct jpeg_error_mgr jerr;
  8.    
  9.         cinfo.err = jpeg_std_error(&jerr);      // 错误处理对象与解码对象绑定
  10.         jpeg_create_decompress(&cinfo);         // 初始化解码器
  11.         jpeg_mem_src(&cinfo, camera->bufs[camera->bufs_index], camera->buf_length);   // 指定JPEG数据的来源
  12.         jpeg_read_header(&cinfo, TRUE);         // 读取图像信息
  13.         cinfo.out_color_space = JCS_RGB;        // 设置解码后的颜色空间为RGB
  14.         jpeg_start_decompress(&cinfo);          // 开始解码
  15.        
  16.         unsigned char *jpeg_line_buf = (char *)malloc(cinfo.output_components * cinfo.output_width);    // 用于存储从JPEG解码器读取的一行数据
  17.         unsigned int *fb_line_buf = (int *)malloc(lcd->line_width);                                     // 用于存储转换后的RGB数据,准备写入framebuffer
  18.     min_width = (cinfo.output_width < lcd->lcd_width) ? cinfo.output_width : lcd->lcd_width;
  19.     min_height = (cinfo.output_height < lcd->lcd_height) ? cinfo.output_height : lcd->lcd_height;
  20.         valid_bytes = min_width * lcd->bpp / 8;             // 一行的有效字节数
  21.         unsigned char *ptr = lcd->fb_base;
  22.     offset_x = ((lcd->lcd_width - min_width) / 2) * lcd->bpp / 8;   // x方向居中
  23.     offset_y = (lcd->lcd_height - min_height) / 2;      // y方向居中
  24.     for (int i = 0; i < offset_y; i++)                  
  25.         ptr += lcd->lcd_width * lcd->bpp / 8;
  26.    
  27.     unsigned int red, green, blue;
  28.     unsigned int color;
  29.         while (cinfo.output_scanline < min_height)
  30.         {
  31.                 jpeg_read_scanlines(&cinfo, &jpeg_line_buf, 1); // 每次读取一行
  32.                 for(int i = 0; i < min_width; i++)              
  33.                 {
  34.                         red = jpeg_line_buf[i * 3];                 
  35.                         green = jpeg_line_buf[i * 3 + 1];           
  36.                         blue = jpeg_line_buf[i * 3 + 2];            
  37.                         color = red << 16 | green << 8 | blue;      // RGB888转RGB8888
  38.                         fb_line_buf[i] = color;
  39.                 }
  40.                 memcpy(ptr + offset_x, fb_line_buf, valid_bytes);   // 将一行数据写入framebuffer
  41.                 ptr += lcd->lcd_width * lcd->bpp / 8;               // 移动到下一行
  42.         }
  43.        
  44.         jpeg_finish_decompress(&cinfo);                     // 完成解码
  45.         jpeg_destroy_decompress(&cinfo);                    // 销毁解码对象
  46.         free(jpeg_line_buf);                                // 释放内存
  47.         free(fb_line_buf);                                  // 释放内存
  48.     return 0;
  49. }
  50. int lcd_init(const char *fb_dev, lcd_mes *lcd){        int screen_size;    struct fb_var_screeninfo var;       if (fb_dev == NULL)        goto _err;    /* 1. open /dev/fb* */            lcd->fd = open(fb_dev, O_RDWR);        if(lcd->fd < 0)        {        printf("can not open %s\n", fb_dev);        goto _err;    }        /* 2. get lcd message */        if (ioctl(lcd->fd, FBIOGET_VSCREENINFO, &var))        {                printf("can not get var\n");                goto _err;        }    screen_size = var.xres * var.yres * var.bits_per_pixel / 8;    lcd->line_width  = var.xres * var.bits_per_pixel / 8;        lcd->lcd_width = var.xres;        lcd->lcd_height = var.yres;        lcd->bpp = var.bits_per_pixel;        lcd->fb_base = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, lcd->fd, 0);        if (lcd->fb_base == (unsigned char *)-1)    {        printf("can not mmap\n");        goto _err;    }    memset(lcd->fb_base, 0x00, screen_size);    return 0;_err:    return -1;}int camera_init(const char *video, camera_mes *camera){       struct v4l2_fmtdesc fmtdesc;    struct v4l2_frmsizeenum fsenum;    int fmt_index = 0;    int frame_index = 0;    int buf_cnt;    int i;    if (video == NULL)        goto _err;    /* 1. open /dev/video* */    camera->fd = open(video, O_RDWR);    if (camera->fd < 0)    {        printf("can not open %s\n", video);        goto _err;    }    /* 2. query capability */    struct v4l2_capability cap;    memset(&cap, 0, sizeof(struct v4l2_capability));    if (0 == ioctl(camera->fd, VIDIOC_QUERYCAP, &cap))    {                if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0)         {            fprintf(stderr, "Error opening device %s: video capture not supported.\n", video);            goto _ioc_querycap_err;        }        if(!(cap.capabilities & V4L2_CAP_STREAMING))         {            fprintf(stderr, "%s does not support streaming i/o\n", video);            goto _ioc_querycap_err;        }    }    else    {        printf("can not get capability\n");        goto _ioc_querycap_err;    }    /* 3. enum formt */    while (1)    {        fmtdesc.index = fmt_index;          fmtdesc.type  = V4L2_BUF_TYPE_VIDEO_CAPTURE;          if (0 != ioctl(camera->fd, VIDIOC_ENUM_FMT, &fmtdesc))            break;        frame_index = 0;        // printf("format %s,%d:\n", fmtdesc.description, fmtdesc.pixelformat);        while (1)        {            memset(&fsenum, 0, sizeof(struct v4l2_frmsizeenum));            fsenum.pixel_format = fmtdesc.pixelformat;            fsenum.index = frame_index;            /* get framesize */            if (ioctl(camera->fd, VIDIOC_ENUM_FRAMESIZES, &fsenum) == 0)            {                // printf("\t%d: %d x %d\n", frame_index, fsenum.discrete.width, fsenum.discrete.height);            }            else            {                break;            }            frame_index++;        }        fmt_index++;    }    /* 4. set formt */    struct v4l2_format fmt;    memset(&fmt, 0, sizeof(struct v4l2_format));    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;    fmt.fmt.pix.width = camera->frame_x_size;    fmt.fmt.pix.height = camera->frame_y_size;    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;    fmt.fmt.pix.field = V4L2_FIELD_ANY;    if (0 == ioctl(camera->fd, VIDIOC_S_FMT, &fmt))    {        // printf("the final frame-size has been set : %d x %d\n", fmt.fmt.pix.width, fmt.fmt.pix.height);        camera->frame_x_size = fmt.fmt.pix.width;        camera->frame_y_size = fmt.fmt.pix.height;        strncpy(camera->fmt, "Motion-JPEG", strlen("Motion-JPEG"));    }    else    {        printf("can not set format\n");        goto _ioc_sfmt_err;    }    /* 5. require buffer */    struct v4l2_requestbuffers rb;    memset(&rb, 0, sizeof(struct v4l2_requestbuffers));    rb.count = 32;    rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;    rb.memory = V4L2_MEMORY_MMAP;    if (0 == ioctl(camera->fd, VIDIOC_REQBUFS, &rb))    {        buf_cnt = rb.count;        for(i = 0; i < rb.count; i++)         {            struct v4l2_buffer buf;            memset(&buf, 0, sizeof(struct v4l2_buffer));            buf.index = i;            buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;            buf.memory = V4L2_MEMORY_MMAP;            if (0 == ioctl(camera->fd, VIDIOC_QUERYBUF, &buf))            {                /* mmap */                camera->bufs[i] = mmap(0, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, camera->fd, buf.m.offset);                if(camera->bufs[i] == MAP_FAILED)                 {                    printf("Unable to map buffer");                    goto _err;                }            }            else            {                printf("can not query buffer\n");                goto _err;            }                    }    }    else    {        printf("can not request buffers\n");        goto _ioc_reqbufs_err;    }    /* 6. queue buffer */    for(i = 0; i < buf_cnt; ++i)     {        struct v4l2_buffer buf;        memset(&buf, 0, sizeof(struct v4l2_buffer));        buf.index = i;        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;        buf.memory = V4L2_MEMORY_MMAP;        if (0 != ioctl(camera->fd, VIDIOC_QBUF, &buf))        {            perror("Unable to queue buffer");            goto _ioc_qbuf_err;        }    }    camera->bufs_index = 0;     // init camera struct    camera->buf_length = 0;    return 0;_ioc_qbuf_err:_ioc_reqbufs_err:_ioc_sfmt_err:_ioc_querycap_err:_err:    return -1;}int main(int argc, char **argv){    int ret;    lcd_mes lcd;    camera_mes camera;    int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;    struct pollfd fds[1];    if (argc != 3)    {        printf("Usage: %s </dev/videoX> </dev/fbX>\n", argv[0]);        return -1;    }    /* lcd init */    ret = lcd_init(argv[2], &lcd);    if (ret == -1)    {        printf("lcd init err !\n");        goto _err;    }    printf("\n-------------- lcd message --------------\n");    printf("screen pixel: %d x %d\n", lcd.lcd_width, lcd.lcd_height);    printf("line width: %d (byte)\n", lcd.line_width);        printf("bpp: %d\n", lcd.bpp);    printf("-----------------------------------------\n");    /* camera init */    camera.frame_x_size = lcd.lcd_width;    camera.frame_y_size = lcd.lcd_height;    ret = camera_init(argv[1], &camera);    if (ret == -1)    {        printf("camera init err !\n");        goto _err;    }    printf("\n------------ camera message -------------\n");    printf("frame size: %d x %d\n", camera.frame_x_size, camera.frame_y_size);    printf("format: %s\n", camera.fmt);    printf("-----------------------------------------\n");    /* start camera */    if (0 != ioctl(camera.fd, VIDIOC_STREAMON, &type))    {        printf("Unable to start capture\n");        goto _err;    }    printf("\nstart camera ...\n");    while (1)    {        /* poll */        memset(fds, 0, sizeof(fds));        fds[0].fd = camera.fd;        fds[0].events = POLLIN;        if (1 == poll(fds, 1, -1))        {            /* dequeue buffer */            struct v4l2_buffer buf;            memset(&buf, 0, sizeof(struct v4l2_buffer));            buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;            buf.memory = V4L2_MEMORY_MMAP;                        if (0 != ioctl(camera.fd, VIDIOC_DQBUF, &buf))            {                printf("Unable to dequeue buffer\n");                goto _ioc_dqbuf_err;            }                        /* jpeg show on lcd */            camera.bufs_index = buf.index;            camera.buf_length = buf.length;            jpeg_show_on_lcd(&lcd, &camera);            /* queue buffer */            if (0 != ioctl(camera.fd, VIDIOC_QBUF, &buf))            {                printf("Unable to queue buffer");                goto _ioc_qbuf_err;            }        }    }    /* close camera */    if (0 != ioctl(camera.fd, VIDIOC_STREAMOFF, &type))    {        printf("Unable to stop capture\n");        goto _ioc_streamoff_err;    }    close(camera.fd);    return 0;_ioc_streamoff_err:_ioc_qbuf_err:_ioc_dqbuf_err:_err:    return -1;}
复制代码
5、测试

5.1、编译应用步伐

假如你使用的buildroot体系,必要交错编译。
这里测试所使用的板子跑的是ubuntu,实行如下下令直接编译:
  1. sudo gcc -o uvctolcd uvctolcd.c -ljpeg
复制代码
5.2、运行应用步伐

  1. sudo ./uvctolcd /dev/video10 /dev/fb0
复制代码


6、总结

参考文章:Linux摄像头(v4l2应用)——在LCD上实时表现摄像头收罗JPEG数据_v4l2调用并表现图像-CSDN博客
源码gitee堆栈:
  1. 仓库主页:
  2. https://gitee.com/cattle_l/v4l2_app.git
  3. 直接拉取:
  4. git clone https://gitee.com/cattle_l/v4l2_app.git
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表