之前用ffmpeg解碼的時候,已經做了硬解碼的處理,比如支持qsv、dxva2、d3d11va等方式進行硬解碼處理,但是當時解碼出來以後,還是重新轉成了QImage來繪制,這樣就大打折扣了,盡管可以看到GPU使用率有了,但是依然耗時的操作還是在CPU繪制顯示,這就顯得很尴尬了,Qt封裝了大部分的opengl的操作,直接做成了QOPenGLWidget,既支持ffmpeg解碼出來的yuyv格式的數據顯示,還支持硬解碼出來的nv12格式的數據顯示,很好很強大,這樣的話就大大減輕了CPU的壓力,專門交給GPU繪制,經過這麼一番徹底的改造,效率提升至少5倍,不要太牛逼!如果開啟了opengl繪制,則對應内存會增加不少,可能opengl繪制需要開辟很多的内存來交換數據吧。
采用GPU顯示需要同時支持yuyv格式和nv12格式,因為有些配置差的電腦,硬解碼很可能歇菜,此時就需要用opengl來直接繪制ffmpeg軟解碼出來的yuyv數據,做到自動切換,這樣就兼容了所有的可能的情況。測試發現ffmpeg4的性能要優于ffmpeg3,64位的性能要優于32位的,在64位的操作系統上,UDP協議性能要優于TCP性能,但是可能會丢包。
下面是本人測試的結果:
測試數據,64位WIN10 32位qt5.7 32位ffmpeg3 6路1080P主碼流 6路子碼流
| 方案 | CPU | 内存 | GPU |
| ------ | ------ | ------ | ------ |
| none none | 12% | 147MB | 0% |
| dxva2 none | 3% | 360MB | 38% |
| d3d11va none | 2% | 277MB | 62% |
| none painter | 30% | 147MB | 0% |
| dxva2 painter | 30% | 360MB | 38% |
| d3d11va painter | 21% | 277MB | 62% |
| none yuyv | 17% | 177MB | 22% |
| dxva2 yuyv | 25% | 400MB | 38% |
| d3d11va yuyv | 18% | 30MB | 65% |
| qsv nv12 | 22% | 970MB | 40% |
| dxva2 nv12 | 20% | 380MB | 40% |
| d3d11va nv12 | 15% | 320MB | 62% |
## 二、功能特點1. 支持多畫面切換,全屏切換等,包括1 4 6 8 9 13 16 25 36 64畫面切換。
2. 支持alt enter全屏,esc退出全屏。
3. 自定義信息框 錯誤框 詢問框 右下角提示框(包含多種格式)。
4. 17套皮膚樣式随意更換,所有樣式全部統一,包括菜單等。
5. 雲台儀表盤鼠标移上去高亮,八個方位精準識别。
6. 底部畫面工具欄(畫面分割切換 截圖聲音等設置)移上去高亮。
7. 可在配置文件更改左上角logo 中文軟件名稱 英文軟件名稱。
8. 封裝了百度地圖,視圖切換,運動軌迹,設備點位,鼠标按下獲取經緯度等。
9. 支持圖片地圖,設備按鈕可以在圖片地圖上自由拖動自動保存位置信息。
10. 在百度地圖和圖片地圖上,雙擊視頻可以預覽攝像頭實時視頻。
11. 堆棧窗體,每個窗體都是個單獨的qwidget,方便編寫自己的代碼。
12. 頂部鼠标右鍵菜單,可動态控制時間CPU 左上角面闆 左下角面闆 右上角面闆 右下角面闆的顯示和隐藏,支持恢複默認布局。
13. 工具欄可以放置多個小圖标和關閉圖标。
14. 左側右側可拖動拉伸,并自動記憶寬高位置,重啟後恢複。
15. 雙擊攝像機節點自動播放視頻,雙擊節點自動依次添加視頻,會自動跳到下一個,雙擊父節點自動添加該節點下的所有視頻。
16. 攝像機節點拖曳到對應窗體播放視頻,同時支持拖曳本地文件直接播放。
17. 視頻畫面窗體支持拖曳交換,瞬間響應。
18. 雙擊節點 拖曳節點 拖曳窗體交換位置,均自動更新url.txt。
19. 支持從url.txt中加載通道視頻播放,自動記憶最後通道對應的視頻,軟件啟動後自動打開播放。
20. 右下角音量條控件,失去焦點自動隐藏,音量條帶靜音圖标。
21. 集成百度在線地圖和離線地圖,可以添加設備對應位置,自動生成地圖,支持縮放和添加覆蓋物等。
22. 視頻拖動到通道窗體外自動删除視頻。
23. 鼠标右鍵可删除當前 所有視頻,截圖當前 所有視頻。
24. 錄像機管理、攝像機管理,可添加删除修改導入導出打印信息,立即應用新的設備信息生成樹狀列表,不需重啟。
25. 在pro文件中可以自由開啟是否加載地圖。
26. 視頻播放可選2種内核自由切換,vlc ffmpeg,均可在pro中設置。
27. 可設置1 4 9 16畫面輪詢,可設置輪詢間隔以及輪詢碼流類型等,直接在主界面底部工具欄右側單擊啟動輪詢按鈕即可,再次單擊停止輪詢。
28. 默認超過10秒鐘未操作自動隐藏鼠标指針。
29. 支持onvif搜素設備,支持任意onvif攝像機,包括但不限于海康大華宇視天地偉業華為等。
30. 支持onvif雲台控制,可上下左右移動雲台攝像機,包括複位和焦距調整等。
31. 同時支持sqlite、mysql、postsql等數據庫。
32. 可保存視頻,可選定時存儲或者單文件存儲,可選存儲間隔時間。
33. 可設置視頻流通信方式tcp udp,可設置視頻解碼是速度優先、質量優先、均衡等。
34. 可設置硬解碼類型,支持qsv、dxva2、d3d11va等。
35. 默認采用opengl繪制視頻,超低的CPU資源占用,支持yuyv和nv12兩種格式繪制,很牛逼。
36. 高度可定制化,用戶可以很方便的在此基礎上衍生自己的功能,支持linux和mac系統。
## 三、效果圖## 四、核心代碼
void NV12OpenGLWidget::initializeGL()
{
initializeOpenGLFunctions();
glDisable(GL_DEPTH_TEST);
//存儲頂點坐标和紋理坐标
static const GLfloat points[] = {-1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
//頂點緩沖對象初始化
vbo.create();
vbo.bind();
vbo.allocate(points, sizeof(points));
//初始化shader
this->initShader();
//初始化textures
this->initTextures();
//初始化顔色
this->initColor();
}
void NV12OpenGLWidget::paintGL()
{
if (!dataY || !dataUV || width == 0 || height == 0) {
this->initColor();
return;
}
program.bind();
program.enableAttributeArray("vertexIn");
program.enableAttributeArray("textureIn");
program.setAttributeBuffer("vertexIn", GL_FLOAT, 0, 2, 2 * sizeof(GLfloat));
program.setAttributeBuffer("textureIn", GL_FLOAT, 2 * 4 * sizeof(GLfloat), 2, 2 * sizeof(GLfloat));
glActiveTexture(GL_TEXTURE0 1);
glBindTexture(GL_TEXTURE_2D, textureY);
//字節對齊,網上很多代碼都是少了這一步,導緻有時候花屏
glPixelStorei(GL_UNPACK_ROW_LENGTH, linesizeY);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, dataY);
glActiveTexture(GL_TEXTURE0 0);
glBindTexture(GL_TEXTURE_2D, textureUV);
//字節對齊,網上很多代碼都是少了這一步,導緻有時候花屏
glPixelStorei(GL_UNPACK_ROW_LENGTH, linesizeUV >> 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG, width >> 1, height >> 1, 0, GL_RG, GL_UNSIGNED_BYTE, dataUV);
glDrawArrays(GL_QUADS, 0, 4);
program.setUniformValue("textureY", 1);
program.setUniformValue("textureUV", 0);
program.disableAttributeArray("vertexIn");
program.disableAttributeArray("textureIn");
program.release();
}
更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!