首頁 > 軟體

Qt音視訊開發之通用監控佈局控制元件的實現

2023-01-14 14:00:50

一、前言

自從做監控系統以來,就一直有打算將這個功能獨立出來一個類,這樣的話很多系統用到此類佈局切換,通用這個類就行,而且後期此佈局會增加其他異形佈局,甚至按照16:9之類的比例生成佈局,之前此功能直接寫在功能介面UI類中,不方便拓展,好多個系統用到此功能,一旦增加了64佈局、128通道佈局等,都需要做對應更改,煩不勝煩,所以務必將此功能徹底剝離出來,為後面的256通道、異形佈局、自定義佈局打基礎。

通道切換在監控系統中是最基礎的必備功能,一般都會提供1通道、4通道、6通道、8通道、9通道、16通道這幾個通道切換,可能做得比較好的還會提供24通道、32通道、64通道的,這個可能對電腦的設定就有一定要求了,一般來說,超過9個通道實時顯示視訊流,基本上會採用子碼流來顯示,如果都採用主碼流,電腦壓力非常巨大,CPU佔用很高,記憶體也高,不過現在的電腦設定越來越高,基本上四千多塊錢的桌上型電腦,設定已經非常好了,顯示個16個通道的實時視訊毫無壓力。

Qt中的佈局非常好用,尤其是QGridLayout表格佈局,可以指定行列放置控制元件,而且還可以設定每個控制元件佔用幾行幾列,這樣就可以完美的實現各種通道佈局了。比如6通道,可以設定通道1佔用兩行兩列,其他通道各站一行一列即可,當切換佈局的時候,其他隱藏即可。

主要功能:

  • 將所有通道切換處理全部集中到一個類。
  • 通用整數倍數佈局切換函數,可方便拓展到100、255通道等。
  • 通用異形佈局切換函數,可以參考進行自定義異形佈局。
  • 通道佈局切換髮出訊號通知。
  • 可控每種佈局切換選單是否啟用。
  • 支援自定義子選單佈局內容。
  • 支援設定對應的選單標識比如預設的通道字樣改成裝置。

本控制元件開源,開源地址https://gitee.com/feiyangqingyun/QWidgetDemo/tree/master/video/videobox

二、效果圖

三、體驗地址

國內站點:https://gitee.com/feiyangqingyun

國際站點:https://github.com/feiyangqingyun

體驗地址:https://pan.baidu.com/s/1YOVD8nkoOSYwX9KgSauLeQ 提取碼:kcgz 檔名:bin_video_demo/bin_linux_video。

四、相關程式碼

void VideoBox::change_video_normal(int index, int flag)
{
    //首先隱藏所有通道
    hide_video_all();
    int size = 0;
    int row = 0;
    int column = 0;

    //行列數一致的比如 2*2 3*4 4*4 5*5 等可以直接套用通用的公式
    //按照這個函數還可以非常容易的拓展出 10*10 16*16=256 通道介面
    for (int i = 0; i < videoCount; ++i) {
        if (i >= index) {
            //新增到對應佈局並設定可見
            gridLayout->addWidget(widgets.at(i), row, column);
            widgets.at(i)->setVisible(true);

            size++;
            column++;
            if (column == flag) {
                row++;
                column = 0;
            }
        }

        if (size == (flag * flag)) {
            break;
        }
    }
}

void VideoBox::change_video_custom(int index, int type)
{
    //從開始索引開始往後衍生多少個通道
    QList<int> indexs;
    for (int i = index; i < (index + type); ++i) {
        indexs << i;
    }

    if (type == 6) {
        change_video_6(indexs);
    } else if (type == 8) {
        change_video_8(indexs);
    } else if (type == 13) {
        change_video_13(indexs);
    }
}

void VideoBox::change_video_6(const QList<int> &indexs)
{
    //過濾防止索引越界
    if (indexs.size() < 6) {
        return;
    }

    //首先隱藏所有通道
    hide_video_all();
    //挨個重新新增到佈局
    gridLayout->addWidget(widgets.at(indexs.at(0)), 0, 0, 2, 2);
    gridLayout->addWidget(widgets.at(indexs.at(1)), 0, 2, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(2)), 1, 2, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(3)), 2, 2, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(4)), 2, 1, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(5)), 2, 0, 1, 1);
    //設定通道控制元件可見
    for (int i = indexs.first(); i <= indexs.last(); ++i) {
        widgets.at(i)->setVisible(true);
    }
}

void VideoBox::change_video_8(const QList<int> &indexs)
{
    //過濾防止索引越界
    if (indexs.size() < 8) {
        return;
    }

    //首先隱藏所有通道
    hide_video_all();
    //挨個重新新增到佈局
    gridLayout->addWidget(widgets.at(indexs.at(0)), 0, 0, 3, 3);
    gridLayout->addWidget(widgets.at(indexs.at(1)), 0, 3, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(2)), 1, 3, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(3)), 2, 3, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(4)), 3, 3, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(5)), 3, 2, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(6)), 3, 1, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(7)), 3, 0, 1, 1);
    //設定通道控制元件可見
    for (int i = indexs.first(); i <= indexs.last(); ++i) {
        widgets.at(i)->setVisible(true);
    }
}

void VideoBox::change_video_13(const QList<int> &indexs)
{
    //過濾防止索引越界
    if (indexs.size() < 13) {
        return;
    }

    //首先隱藏所有通道
    hide_video_all();
    //挨個重新新增到佈局
    gridLayout->addWidget(widgets.at(indexs.at(0)), 0, 0, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(1)), 0, 1, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(2)), 0, 2, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(3)), 0, 3, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(4)), 1, 0, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(5)), 2, 0, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(6)), 1, 1, 2, 2);
    gridLayout->addWidget(widgets.at(indexs.at(7)), 1, 3, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(8)), 2, 3, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(9)), 3, 0, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(10)), 3, 1, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(11)), 3, 2, 1, 1);
    gridLayout->addWidget(widgets.at(indexs.at(12)), 3, 3, 1, 1);
    //設定通道控制元件可見
    for (int i = indexs.first(); i <= indexs.last(); ++i) {
        widgets.at(i)->setVisible(true);
    }
}

void VideoBox::change_video_1(int index)
{
    //首先隱藏所有通道
    hide_video_all();
    //新增通道到佈局
    gridLayout->addWidget(widgets.at(index), 0, 0);
    //設定可見
    widgets.at(index)->setVisible(true);
}

void VideoBox::change_video_4(int index)
{
    change_video_normal(index, 2);
}

void VideoBox::change_video_6(int index)
{
    change_video_custom(index, 6);
}

void VideoBox::change_video_8(int index)
{
    change_video_custom(index, 8);
}

void VideoBox::change_video_9(int index)
{
    change_video_normal(index, 3);
}

void VideoBox::change_video_13(int index)
{
    change_video_custom(index, 13);
}

void VideoBox::change_video_16(int index)
{
    change_video_normal(index, 4);
}

void VideoBox::change_video_25(int index)
{
    change_video_normal(index, 5);
}

void VideoBox::change_video_36(int index)
{
    change_video_normal(index, 6);
}

void VideoBox::change_video_64(int index)
{
    change_video_normal(index, 8);
}

五、功能特點

5.1 基礎功能

  • 支援各種音訊視訊檔格式,比如mp3、wav、mp4、asf、rm、rmvb、mkv等。
  • 支援本地攝像頭裝置,可指定解析度、影格率。
  • 支援各種視訊流格式,比如rtp、rtsp、rtmp、http等。
  • 本地音視訊檔和網路音視訊檔,自動識別檔案長度、播放進度、音量大小、靜音狀態等。
  • 檔案可以指定播放位置、調節音量大小、設定靜音狀態等。
  • 支援倍速播放檔案,可選0.5倍、1.0倍、2.5倍、5.0倍等速度,相當於慢放和快放。
  • 支援開始播放、停止播放、暫停播放、繼續播放。
  • 支援抓拍截圖,可指定檔案路徑,可選抓拍完成是否自動顯示預覽。
  • 支援錄影儲存,手動開始錄影、停止錄影,部分核心支援暫停錄影後繼續錄影,跳過不需要錄影的部分。
  • 支援無感知切換回圈播放、自動重連等機制。
  • 提供播放成功、播放完成、收到解碼圖片、收到抓拍圖片、視訊尺寸變化、錄影狀態變化等訊號。
  • 多執行緒處理,一個解碼一個執行緒,不卡主介面。

5.2 特色功能

  • 同時支援多種解碼核心,包括qmedia核心(Qt4/Qt5/Qt6)、ffmpeg核心(ffmpeg2/ffmpeg3/ffmpeg4/ffmpeg5)、vlc核心(vlc2/vlc3)、mpv核心(mpv1/mp2)、海康sdk、easyplayer核心等。
  • 非常完善的多重基礎類別設計,新增一種解碼核心只需要實現極少的程式碼量,就可以應用整套機制。
  • 同時支援多種畫面顯示策略,自動調整(原始解析度小於顯示控制元件尺寸則按照原始解析度大小顯示,否則等比例縮放)、等比例縮放(永遠等比例縮放)、拉伸填充(永遠拉伸填充)。所有核心和所有視訊顯示模式下都支援三種畫面顯示策略。
  • 同時支援多種視訊顯示模式,控制程式碼模式(傳入控制元件控制程式碼交給對方繪製控制)、繪製模式(回撥拿到資料後轉成QImage用QPainter繪製)、GPU模式(回撥拿到資料後轉成yuv用QOpenglWidget繪製)。
  • 支援多種硬體加速型別,ffmpeg可選dxva2、d3d11va等,mpv可選auto、dxva2、d3d11va,vlc可選any、dxva2、d3d11va。不同的系統環境有不同的型別選擇,比如linux系統有vaapi、vdpau,macos系統有videotoolbox。
  • 解碼執行緒和顯示錶單分離,可指定任意解碼核心掛載到任意顯示錶單,動態切換。
  • 支援共用解碼執行緒,預設開啟並且自動處理,當識別到相同的視訊地址,共用一個解碼執行緒,在網路視訊環境中可以大大節約網路流量以及對方裝置的推流壓力。國內頂尖視訊廠商均採用此策略。這樣只要拉一路視訊流就可以共用到幾十個幾百個通道展示。
  • 自動識別視訊旋轉角度並繪製,比如手機上拍攝的視訊一般是旋轉了90度的,播放的時候要自動旋轉處理,不然預設是倒著的。
  • 自動識別視訊流播放過程中解析度的變化,在視訊控制元件上自動調整尺寸。比如攝像機可以在使用過程中動態設定解析度,當解析度改動後對應視訊控制元件也要做出同步反應。
  • 音視訊檔無感知自動切換回圈播放,不會出現切換期間黑畫面等肉眼可見的切換痕跡。
  • 視訊控制元件同時支援任意解碼核心、任意畫面顯示策略、任意視訊顯示模式。
  • 視訊控制元件懸浮條同時支援控制程式碼、繪製、GPU三種模式,非絕對座標移來移去。
  • 本地攝像頭裝置支援指定裝置名稱、解析度、影格率進行播放。
  • 錄影檔案同時支援開啟的視訊檔、本地攝像頭、網路視訊流等。
  • 瞬間響應開啟和關閉,無論是開啟不存在的視訊或者網路流,探測裝置是否存在,讀取中的超時等待,收到關閉指令立即中斷之前的操作並響應。
  • 支援開啟各種圖片檔案,支援本地音視訊檔拖曳播放。
  • 視訊控制元件懸浮條自帶開始和停止錄影切換、聲音靜音切換、抓拍截圖、關閉視訊等功能。
  • 音訊元件支援聲音波形值資料解析,可以根據該值繪製波形曲線和柱狀聲音條,預設提供了聲音振幅訊號。
  • 各元件中極其詳細的列印資訊提示,尤其是報錯資訊提示,封裝的統一列印格式。針對現場複雜的裝置環境測試極其方便有用,相當於精確定位到具體哪個通道哪個步驟出錯。
  • 程式碼框架和結構優化到最優,效能強悍,持續迭代更新升級。
  • 原始碼支援Qt4、Qt5、Qt6,相容所有版本。

5.3 視訊控制元件

  • 可動態新增任意多個osd標籤資訊,標籤資訊包括名字、是否可見、字號大小、文字文字、文字顏色、標籤圖片、標籤座標、標籤格式(文字、日期、時間、日期時間、圖片)、標籤位置(左上角、左下角、右上角、右下角、居中、自定義座標)。
  • 可動態新增任意多個圖形資訊,這個非常有用,比如人工智慧演演算法解析後的圖形區域資訊直接發給視訊控制元件即可。圖形資訊支援任意形狀,直接繪製在原始圖片上,採用絕對座標。
  • 圖形資訊包括名字、邊框大小、邊框顏色、背景顏色、矩形區域、路徑集合、點座標集合等。
  • 每個圖形資訊都可指定三種區域中的一種或者多種,指定了的都會繪製。
  • 內建懸浮條控制元件,懸浮條位置支援頂部、底部、左側、右側。
  • 懸浮條控制元件引數包括邊距、間距、背景透明度、背景顏色、文字顏色、按下顏色、位置、按鈕圖示程式碼集合、按鈕名稱標識集合、按鈕提示資訊集合。
  • 懸浮條控制元件一排工具按鈕可自定義,通過結構體引數設定,圖示可選圖形字型還是自定義圖片。
  • 懸浮條按鈕內部實現了錄影切換、抓拍截圖、靜音切換、關閉視訊等功能,也可以自行在原始碼中增加自己對應的功能。
  • 懸浮條按鈕對應實現了功能的按鈕,有對應圖示切換處理,比如錄影按鈕按下後會切換到正在錄影中的圖示,聲音按鈕切換後變成靜音圖示,再次切換還原。
  • 懸浮條按鈕單擊後都用名稱唯一標識作為訊號發出,可以自行關聯響應處理。
  • 懸浮條空白區域可以顯示提示資訊,預設顯示當前視訊解析度大小,可以增加影格率、碼流大小等資訊。
  • 視訊控制元件引數包括邊框大小、邊框顏色、焦點顏色、背景顏色(預設透明)、文字顏色(預設全域性文字顏色)、填充顏色(視訊外的空白處填充黑色)、背景文字、背景圖片(如果設定了圖片優先取圖片)、是否拷貝圖片、縮放顯示模式(自動調整、等比例縮放、拉伸填充)、視訊顯示模式(控制程式碼、繪製、GPU)、啟用懸浮條、懸浮條尺寸(橫向為高度、縱向為寬度)、懸浮條位置(頂部、底部、左側、右側)。

5.4 核心ffmpeg

  • 支援各種音視訊檔、本地攝像頭裝置,各種視訊流網路流。
  • 支援開始播放、暫停播放、繼續播放、停止播放、設定播放進度、倍速播放。
  • 可設定音量、靜音切換、抓拍圖片、錄影儲存。
  • 自動提取專輯資訊比如標題、藝術家、專輯、專輯封面,自動顯示專輯封面。
  • 完美支援音視訊同步和倍速播放。
  • 解碼策略支援速度優先、質量優先、均衡處理、最快速度。
  • 支援手機視訊旋轉角度顯示,比如一般手機拍攝的視訊是旋轉了90度的,解碼顯示的時候需要重新旋轉90度才是正的。
  • 自動轉換yuv420格式,比如本地攝像頭是yuyv422格式,有些視訊檔是xx格式,統一將非yuv420格式轉換,然後再進行處理。
  • 支援硬解碼dxva2、d3d11va等,效能極高尤其是大解析度比如4K視訊。
  • 視訊響應極低延遲0.2s左右,極速響應開啟視訊流0.5s左右,專門做了優化處理。
  • 硬解碼和GPU繪製組合,極低CPU佔用,比海康大華等使用者端更優。
  • 支援視訊流中的各種音訊格式,AAC、PCM、G.726、G.711A、G.711Mu、G.711ulaw、G.711alaw、MP2L2等都支援,推薦選擇AAC相容性跨平臺性最好。
  • 視訊儲存支援yuv、h264、mp4多種格式,音訊儲存支援pcm、wav、aac多種格式。預設視訊mp4格式、音訊aac格式。
  • 支援分開儲存音訊視訊檔,也支援合併到一個mp4檔案,預設策略是無論何種音視訊檔格式儲存,最終都轉成mp4及aac格式,然後合併成音視訊一起的mp4檔案。
  • 支援本地攝像頭實時視訊顯示帶音訊輸入輸出,音視訊錄製合併到一個mp4檔案。
  • 支援H264/H265編碼(現在越來越多的監控攝像頭是H265視訊流格式)生成視訊檔,內部自動識別切換編碼格式。
  • 自動識別視訊流動態解析度改動,重新開啟視訊流。
  • 支援使用者資訊中包含特殊字元(比如使用者資訊中包含+#@等字元)的視訊流播放,內建解析跳脫處理。
  • 純qt+ffmpeg解碼,非sdl等第三方繪製播放依賴,gpu繪製採用qopenglwidget,音訊播放採用qaudiooutput。
  • 同時支援ffmpeg2、ffmpeg3、ffmpeg4、ffmpeg5版本,全部做了相容處理。如果需要支援xp需要選用ffmpeg3及以下。

以上就是Qt音視訊開發之通用監控佈局控制元件的實現的詳細內容,更多關於Qt監控佈局控制元件的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com