1六、視頻的採集和動態顯示

1、V4l2更新緩衝Buffer的方法緩存

 回顧上一節中,咱們使用v4l2控制usb 攝像頭,對攝像頭的靜態圖片採集流程操做過程能夠概括爲圖1:ide

圖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命令ui

因此爲了實現緩存區圖像數據的動態更新,須要在每一次處理完數據後使用VIDIOC_QBUF更新緩存區,以便下一次VIDIOC_DQBUF獲取到新的一幀數據。於是動態更新緩存的視頻採集流程應該如圖3所示:spa

 

圖3 動態視頻採集流程code

 爲此,須要從新定義兩個函數,一個咱們定義爲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釋放視頻幀,讓出緩存空間準備新的視頻幀數據:blog

 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 }

2、Qt的paintEvent事件事件

在上篇博客裏面,咱們對採集的的視頻幀數據的顯示,採用的方法是使用了一個QLabel和QPixmap,並使用loadfromdata函數將採集的數據轉爲QPixmap中的數據,並顯示到QLabel上。這樣的作法致使的結果是QLabel和QPixmap數據只能被更新一次,因此只能顯示靜態圖片。

在完成了視頻緩存數據更新後,咱們所面臨的問題就是怎麼樣才能把這個數據動態顯示出來。好在Qt提供了窗口刷新事件paintEvent,在這裏,咱們可使用兩種方式觸發paintEvent事件:

一、使用定時器QTimer,定時爲33ms(由於攝像頭的幀頻爲30pfs);

二、不使用定時器,由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 }

3、測試效果

相關文章
相關標籤/搜索