超群天晴

【原创】基于ZedBoard的Webcam设计(三):视频的采集和动态显示

0
阅读(7672)

(原创)基于ZedBoard的Webcam设计(一):USB摄像头(V4L2接口)的图片采集(原创)基于ZedBoard的Webcam设计(二):USB摄像头图片采集+QT显示两篇博客中,我们完成了ZedBoard上USB摄像头的图片采集,以及将图片显示到Qt界面上。可是毕竟采集和显示到只是一帧图像,并非动态的视频数据。本小节将在介绍V4L2更新视频缓冲的方式、Qt paintEvent更新控件的基础上,实现如何实现视频的动态显示。

更多更新请关注我的博客:@超群天晴http://www.cnblogs.com/surpassal/

相关阅读

(原创)基于ZedBoard的Webcam设计(一):USB摄像头(V4L2接口)的图片采集

(原创)基于ZedBoard的Webcam设计(二):USB摄像头图片采集+QT显示

(原创)基于ZedBoard的Webcam设计(三):视频的采集和动态显示

(原创)基于ZedBoard的Webcam设计(四):MJPG编码和AVI封装

(原创)基于ZedBoard的Webcam设计(五):x264编码在zedboard上的实现(软编码)

硬件平台:Digilent ZedBoard

开发环境:Windows XP 32 bit + Wmare 8.0 + Ubuntu 10.04 +Qt+ arm-linux-xilinx-gnueabi交叉编译环境

Zedboard linux:Digilent OOB Design

一、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获取视频帧:

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

复制代码

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

复制代码
1intVideoDevice::free_frame()
2{
3if(index != -1)
4{
5v4l2_buffer queue_buf;
6queue_buf.type =V4L2_BUF_TYPE_VIDEO_CAPTURE;
7queue_buf.memory =V4L2_MEMORY_MMAP;
8queue_buf.index =index;
9
10if(ioctl(fd,VIDIOC_QBUF, &queue_buf) == -1)
11{
12returnFALSE;
13}
14returnTRUE;
15}
16returnFALSE;
17}

复制代码

二、Qt的paintEvent事件

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

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

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

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

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

复制代码

三、测试效果

在ubuntu上测试通过后,移植到Zedboard上进行测试,测试视频:

http://v.youku.com/v_show/id_XNDk3OTcxNzE2.html

==================================

代码整理中,现提供可执行文件:zed_webcam_lab3.rar

Baidu
map