一、前言
硬件加速這個功能在一年多以前就已經具備,當時對兩個內核一個是ffmpeg內核、一個是vlc內核都做了對應的接口函數,只是當時為了簡單沒有在系統設置中做出接口,vlc做硬件加速不用自己寫代碼實現,畢竟vlc是在ffmpeg基礎上又增加了一層殼,硬件加速那塊的功能都vlc自己內部實現了,只需要設置參數傳進去即可,而ffmpeg需要自己根據對應的函數來實現解碼,這個網上搜索能找到很多類似的答案的,推薦看雷神的博客,講得非常詳細,在國內ffmpeg的分析文章博客這塊,神一般的存在。ffmpeg自帶demo中有硬件加速的代碼,根據他的代碼直接抄過來就可以,ffmpeg支持qsv、vaapi、vdpau、dxva2、d3d11va幾種,vlc支持auto、any、vdpau、dxva2、d3d11va這幾種,推薦在windows上使用d3d11va。
對應硬件加速還有個叫硬件解碼,一般都是專門的音視頻硬件來處理,比如海思的芯片,這個在安防視頻監控領域很常見,畢竟通過GPU也好硬件加速也好,要並發處理大量的視頻流信息,大量占用系統資源不大好,還是直接專門的解碼芯片處理更方便,速度也更快,而且絲毫不影響系統正常運行,這種專有的視頻解碼芯片都會提供對應的頭文件給你調用,你只需要按照手冊進行編寫即可,這種不具有通用性,依賴具體的硬件芯片。
其實硬件加速也需要硬件支持,比如沒有GPU的芯片,那就肯定沒法搞硬件加速,一般現在的X86的芯片都會有GPU的,要支撐各種大型游戲的正常運行肯定要不錯的GPU運算能力才行,所以后面才會出現獨立顯卡,專門用來顯示加速,一套系統穩定性第一位,流暢性可能就是其次了,如果在使用軟件系統的過程中一卡一卡的,相信沒有幾個用戶心理舒服。
電腦硬件加速即是利用硬件模塊來代替軟件算法以補充利用硬件所固有的快速特性。簡單的說就是利用顯卡的GPU來代替CPU處理,顯卡的GPU在處理速度上圓圓高於CPU,因此有很多人啟用硬件加速來加速顯卡的流暢度。由於中央處理器的結構使得它能夠在短時間內完成各種各樣不同的指令。它能夠處理什么指令主要由軟件限制。但是由於中央處理器的結構有些重復任務無法非常有效和迅速地被處理。通過使用專門為這樣的重復任務設計的特殊硬件元件(芯片或者處理器,通常是用GPU完成)可以解決這個問題。這些特殊硬件元件不必像中央處理器那樣靈活,因此它們的硬件設計就已經顧及了優化處理這些特殊問題的需要,這樣一來中央處理器有時間去處理其它任務。
視頻控件開源地址:https://gitee.com/feiyangqingyun/QWidgetDemo https://github.com/feiyangqingyun/QWidgetDemo
文件名稱:videowidget
體驗地址:https://gitee.com/feiyangqingyun/QWidgetExe https://github.com/feiyangqingyun/QWidgetExe
文件名稱:bin_video_system.zip
二、功能特點
- 支持16畫面切換,全屏切換等,包括1+4+6+8+9+13+16畫面切換。
- 支持alt+enter全屏,esc退出全屏。
- 自定義信息框+錯誤框+詢問框+右下角提示框。
- 17套皮膚樣式隨意更換,所有樣式全部統一,包括菜單等。
- 雲台儀表盤鼠標移上去高亮,八個方位精准識別。
- 底部畫面工具欄(畫面分割切換+截圖聲音等設置)移上去高亮。
- 可在配置文件更改左上角logo+中文軟件名稱+英文軟件名稱。
- 封裝了百度地圖,視圖切換,設備點位,鼠標按下獲取經緯度等。
- 堆棧窗體,每個窗體都是個單獨的qwidget,方便編寫自己的代碼。
- 頂部鼠標右鍵菜單,可動態控制時間CPU+左上角面板+左下角面板+右上角面板+右下角面板的顯示和隱藏,支持恢復默認布局。
- 工具欄可以放置多個小圖標和關閉圖標。
- 左側右側可拖動拉伸,並自動記憶寬高位置,重啟后恢復。
- 雙擊攝像機節點自動播放視頻,雙擊節點自動依次添加視頻,會自動跳到下一個,雙擊父節點自動添加該節點下的所有視頻。
- 攝像機節點拖曳到對應窗體播放視頻,同時支持拖曳本地文件直接播放。
- 視頻畫面窗體支持拖曳交換,瞬間響應。
- 雙擊節點+拖曳節點+拖曳窗體交換位置,均自動更新url.txt。
- 支持從url.txt中加載16通道視頻播放,自動記憶最后通道對應的視頻,軟件啟動后自動打開播放。
- 右下角音量條控件,失去焦點自動隱藏,音量條帶靜音圖標。
- 集成百度在線地圖和離線地圖,可以添加設備對應位置,自動生成地圖,支持縮放和添加覆蓋物等。
- 視頻拖動到通道窗體外自動刪除視頻。
- 鼠標右鍵可刪除當前+所有視頻,截圖當前+所有視頻。
- 錄像機管理、攝像機管理,可添加刪除修改導入導出打印信息,立即應用新的設備信息生成樹狀列表,不需重啟。
- 在pro文件中可以自由開啟是否加載地圖。
- 視頻播放可選四種內核自由切換,vlc+ffmpeg+easyplayer+海康sdk,均可在pro中設置。
- 可設置1+4+9+16畫面輪詢,可設置輪詢間隔以及輪詢碼流類型等,直接在主界面底部工具欄右側單擊啟動輪詢按鈕即可,再次單擊停止輪詢。
- 默認超過10秒鍾未操作自動隱藏鼠標指針。
- 支持onvif搜素設備,支持任意onvif攝像機,包括但不限於海康大華宇視天地偉業華為等,支持onvif雲台控制。
- 高度可定制化,用戶可以很方便的在此基礎上衍生自己的功能,支持linux系統。
三、效果圖
四、核心代碼
int FFmpegThread::decode_packet(AVCodecContext *avctx, AVPacket *packet)
{
#ifndef gcc45
int ret = 0;
ret = avcodec_send_packet(avctx, packet);
if (ret < 0) {
qDebug() << TIMEMS << "Error during decoding";
return ret;
}
while (ret >= 0) {
ret = avcodec_receive_frame(avctx, avFrame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
qDebug() << TIMEMS << "Error during decoding";
break;
}
ret = av_hwframe_transfer_data(avFrame2, avFrame, 0);
if (ret < 0) {
qDebug() << TIMEMS << "Error transferring the data to system memory";
av_frame_unref(avFrame2);
av_frame_unref(avFrame);
return ret;
}
}
#endif
return 1;
}
static AVPixelFormat get_qsv_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_fmts)
{
#ifndef gcc45
while (*pix_fmts != AV_PIX_FMT_NONE) {
if (*pix_fmts == AV_PIX_FMT_QSV) {
DecodeContext *decode = (DecodeContext *)avctx->opaque;
avctx->hw_frames_ctx = av_hwframe_ctx_alloc(decode->hw_device_ref);
if (!avctx->hw_frames_ctx) {
return AV_PIX_FMT_NONE;
}
AVHWFramesContext *frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data;
AVQSVFramesContext *frames_hwctx = (AVQSVFramesContext *)frames_ctx->hwctx;
frames_ctx->format = AV_PIX_FMT_QSV;
frames_ctx->sw_format = avctx->sw_pix_fmt;
frames_ctx->width = FFALIGN(avctx->coded_width, 32);
frames_ctx->height = FFALIGN(avctx->coded_height, 32);
frames_ctx->initial_pool_size = 32;
frames_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
int ret = av_hwframe_ctx_init(avctx->hw_frames_ctx);
if (ret < 0) {
return AV_PIX_FMT_NONE;
}
return AV_PIX_FMT_QSV;
}
pix_fmts++;
}
#endif
qDebug() << TIMEMS << "The QSV pixel format not offered in get_format()";
return AV_PIX_FMT_NONE;
}
enum AVPixelFormat hw_pix_fmt;
static enum AVPixelFormat get_hw_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts)
{
const enum AVPixelFormat *p;
for (p = pix_fmts; *p != -1; p++) {
if (*p == hw_pix_fmt) {
return *p;
}
}
qDebug() << TIMEMS << "Failed to get HW surface format";
return AV_PIX_FMT_NONE;
}