zoukankan      html  css  js  c++  java
  • 16、视频的采集和动态显示

    一、V4l2更新缓冲Buffer的方法

     回顾上一节中,我们使用v4l2控制usb 摄像头,对摄像头的静态图片采集流程操作过程可以归纳为图1:

    图1 静态图片采集流程图

    所用到的函数和参数都在旁边标注出。可以看到使用命令VIDIOC_DQBUF将缓存中的图像帧取出,然后摄像头设备是一直在采集图像,如果没有更新缓存区命令,采集到的新数据是不会被更新到缓存中的。v4l2提供了与VIDIOC_DQBUF命令相对的命令VIDIOC_QBUF,我对这个命令的理解就是允许摄像头设备将采集图像更新到缓存区。假设开辟的缓存FIFO大小为4帧,如图2(a),当使用VIDIOC_DQBUF命令后,当前帧n从FIFO中取走,FIFO留下一个空缺,如图2(b),这种情况下如果使用VIDIOC_QBUF命令,新一帧n+4将被写入缓存,如图2(c)。

    图2 缓存FIFO与VIDIOC_DQBUF命令、VIDIOC_QBUF命令

    所以为了实现缓存区图像数据的动态更新,需要在每一次处理完数据后使用VIDIOC_QBUF更新缓存区,以便下一次VIDIOC_DQBUF获取到新的一帧数据。因而动态更新缓存的视频采集流程应该如图3所示:

     

    图3 动态视频采集流程

     为此,需要重新定义两个函数,一个我们定义为get_frame获取视频帧:

     1 int VideoDevice::get_frame(void **frame_buf, size_t* len)
     2 {
     3     v4l2_buffer queue_buf;
     4 
     5     queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     6     queue_buf.memory = V4L2_MEMORY_MMAP;
     7 
     8     if(ioctl(fd, VIDIOC_DQBUF, &queue_buf) == -1)
     9     {
    10         return FALSE;
    11     }
    12 
    13     *frame_buf = buffers[queue_buf.index].start;
    14     *len = buffers[queue_buf.index].length;
    15     index = queue_buf.index;
    16 
    17     return TRUE;
    18 }

    再定义free_frame释放视频帧,让出缓存空间准备新的视频帧数据:

     1 int VideoDevice::free_frame()
     2 {
     3     if(index != -1)
     4     {
     5         v4l2_buffer queue_buf;
     6         queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     7         queue_buf.memory = V4L2_MEMORY_MMAP;
     8         queue_buf.index = index;
     9 
    10         if(ioctl(fd, VIDIOC_QBUF, &queue_buf) == -1)
    11         {
    12             return FALSE;
    13         }
    14         return TRUE;
    15     }
    16     return FALSE;
    17 }

    二、Qt的paintEvent事件

    在上篇博客里面,我们对采集的的视频帧数据的显示,采用的方法是使用了一个QLabel和QPixmap,并使用loadfromdata函数将采集的数据转为QPixmap中的数据,并显示到QLabel上。这样的做法导致的结果是QLabel和QPixmap数据只能被更新一次,所以只能显示静态图片。

    在完成了视频缓存数据更新后,我们所面临的问题就是怎么样才能把这个数据动态显示出来。好在Qt提供了窗口刷新事件paintEvent,在这里,我们可以使用两种方式触发paintEvent事件:

    1、使用定时器QTimer,定时为33ms(因为摄像头的帧频为30pfs);

    2、不使用定时器,由QLabel自身内容改变产生。这里采用这种方式。paintEvent函数内容:

     1 void Widget::paintEvent(QPaintEvent *)
     2 {
     3     rs = vd->get_frame((void **)&yuv_buffer,&len);
     4     convert_yuv_to_rgb_buffer(yuv_buffer,rgb_buffer,640,480);
     5 
     6     frame->loadFromData((uchar *)rgb_buffer,640 * 480 * 3);
     7 
     8     ui->label->setPixmap(QPixmap::fromImage(*frame,Qt::AutoColor));
     9 
    10     rs = vd->unget_frame();
    11 }

    三、测试效果

  • 相关阅读:
    手机号码正则表达式
    POJ 3233 Matrix Power Series 矩阵快速幂
    UVA 11468
    UVA 1449
    HDU 2896 病毒侵袭 AC自动机
    HDU 3065 病毒侵袭持续中 AC自动机
    HDU 2222 Keywords Search AC自动机
    POJ 3461 Oulipo KMP模板题
    POJ 1226 Substrings KMP
    UVA 1455 Kingdom 线段树+并查集
  • 原文地址:https://www.cnblogs.com/liusiluandzhangkun/p/8690784.html
Copyright © 2011-2022 走看看