網(wǎng)站建設(shè)論文的摘要免費(fèi)b站推廣網(wǎng)站入口
一、前言
通用懸浮按鈕工具欄這個(gè)功能經(jīng)過了好幾個(gè)版本的迭代,一開始設(shè)計(jì)的時(shí)候是寫在視頻控件widget窗體中,當(dāng)時(shí)功能簡單就放一排按鈕在頂部懸浮widget中就好,隨著用戶需求的變化,用戶需要自定義懸浮條的要求越發(fā)強(qiáng)烈,而且部分用戶還希望懸浮條的位置能夠指定,比如可以在頂部、底部、左側(cè)、右側(cè)位置。為了滿足各種需求,特意將通用懸浮按鈕工具欄單獨(dú)成類BannerWidget,將所有懸浮條參數(shù)放到結(jié)構(gòu)體BannerPara中,可以設(shè)置按鈕的間距、邊距、背景透明度、背景顏色、文本顏色、按下顏色、懸浮條位置等,每個(gè)按鈕都對應(yīng)有圖標(biāo)代碼、名稱標(biāo)識、提示信息。這些信息都可以動態(tài)設(shè)置并立即應(yīng)用,在最外層的視頻控件窗體就提供了設(shè)置接口。
//懸浮條位置
enum BannerPosition {BannerPosition_Top = 0, //頂部BannerPosition_Bottom = 1, //底部BannerPosition_Left = 2, //左側(cè)BannerPosition_Right = 3 //右側(cè)
};//懸浮條參數(shù)
#include <QMargins>
struct BannerPara {QMargins margin; //邊距int spacing; //間距int bgAlpha; //背景透明度QColor bgColor; //背景顏色QColor textColor; //文本顏色QColor pressColor; //按下顏色BannerPosition position; //懸浮條位置QList<int> icons; //按鈕圖標(biāo)代碼集合QList<QString> names; //按鈕名稱標(biāo)識集合QList<QString> tips; //按鈕提示信息集合BannerPara() {margin = QMargins(5, 0, 3, 0);spacing = 2;bgAlpha = 200;bgColor = "#333333";textColor = "#FFFFFF";pressColor = "#5EC7D9";position = BannerPosition_Top;//采用iconfont圖形字體icons = QList<int>() << 0xea1b << 0xeb15 << 0xe674 << 0xea36 << 0xe74c;//為了避免和其他控件重名建議前面加上前綴用來區(qū)分names = QList<QString>() << "banner_btnRecord" << "banner_btnSnap" << "banner_btnSound" << "banner_btnAlarm" << "banner_btnClose";tips = QList<QString>() << "錄制" << "抓圖" << "聲音" << "警情" << "關(guān)閉";}
};
二、效果圖
三、體驗(yàn)地址
- 國內(nèi)站點(diǎn):https://gitee.com/feiyangqingyun
- 國際站點(diǎn):https://github.com/feiyangqingyun
- 個(gè)人作品:https://blog.csdn.net/feiyangqingyun/article/details/97565652
- 體驗(yàn)地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取碼:01jf 文件名:bin_video_demo/bin_linux_video。
四、相關(guān)代碼
void BannerWidget::btnClicked()
{QPushButton *btn = (QPushButton *)sender();QString objName = btn->objectName();emit btnClicked(objName);//根據(jù)需要切換圖標(biāo)以及標(biāo)識if (objName.endsWith("btnRecord")) {btn->setText((QChar)0xea1c);btn->setObjectName(objName.replace("Record", "Stop"));} else if (objName.endsWith("btnStop")) {btn->setText((QChar)0xea1b);btn->setObjectName(objName.replace("Stop", "Record"));} else if (objName.endsWith("btnSound")) {btn->setText((QChar)0xe667);btn->setObjectName(objName.replace("Sound", "Muted"));} else if (objName.endsWith("btnMuted")) {btn->setText((QChar)0xe674);btn->setObjectName(objName.replace("Muted", "Sound"));}
}void BannerWidget::receivePlayFinsh()
{this->changeStatus("Stop", "Record", 0xea1b);this->changeStatus("Muted", "Sound", 0xe674);
}void BannerWidget::receiveMuted(bool muted)
{if (muted) {this->changeStatus("Sound", "Muted", 0xe667);} else {this->changeStatus("Muted", "Sound", 0xe674);}
}void BannerWidget::recorderStateChanged(const RecorderState &state, const QString &file)
{if (state == RecorderState_Recording) {this->isRecord = true;this->changeStatus("Record", "Stop", 0xea1c);} else if (state == RecorderState_Stopped) {this->isRecord = false;this->changeStatus("Stop", "Record", 0xea1b);}this->showInfo(text);
}void BannerWidget::setBannerPara(const BannerPara &bannerPara)
{this->bannerPara = bannerPara;
}void BannerWidget::initButton()
{//檢查數(shù)量是否一致int iconCount = bannerPara.icons.size();int nameCount = bannerPara.names.size();if (iconCount == 0 || iconCount != nameCount) {return;}//清空之前的按鈕對象qDeleteAll(btns);btns.clear();//如果之前存在布局則刪除布局(居然只能用delete而不是deleteLater)if (this->layout()) {delete this->layout();}//識別當(dāng)前用哪個(gè)布局bool vertical = (bannerPara.position == BannerPosition_Left || bannerPara.position == BannerPosition_Right);//實(shí)例化布局QBoxLayout *layout = 0;if (vertical) {layout = new QVBoxLayout;//插入彈簧并設(shè)置布局的邊距間距layout->addStretch();} else {layout = new QHBoxLayout;//插入標(biāo)簽放置各種信息layout->addWidget(label);}layout->setContentsMargins(bannerPara.margin);layout->setSpacing(bannerPara.spacing);this->setLayout(layout);//有多種辦法來設(shè)置圖片,qt內(nèi)置的圖標(biāo)+自定義的圖標(biāo)+圖形字體//既可以設(shè)置圖標(biāo)形式,也可以直接圖形字體設(shè)置文本
#if 0QList<QIcon> icons;icons << QApplication::style()->standardIcon(QStyle::SP_ComputerIcon);icons << QApplication::style()->standardIcon(QStyle::SP_FileIcon);icons << QApplication::style()->standardIcon(QStyle::SP_DirIcon);icons << QApplication::style()->standardIcon(QStyle::SP_DialogOkButton);icons << QApplication::style()->standardIcon(QStyle::SP_DialogCancelButton);
#endif//根據(jù)位置設(shè)置布局以及添加按鈕(如果不需要按鈕則只需要加一行 iconCount = 0)for (int i = 0; i < iconCount; ++i) {QPushButton *btn = new QPushButton;//綁定按鈕單擊事件,用來發(fā)出信號通知connect(btn, SIGNAL(clicked(bool)), this, SLOT(btnClicked()));//設(shè)置標(biāo)識,用來區(qū)別按鈕btn->setObjectName(bannerPara.names.at(i));//設(shè)置提示文字信息btn->setToolTip(bannerPara.tips.at(i));if (vertical) {//設(shè)置固定高度btn->setFixedHeight(20);//設(shè)置拉伸策略使得填充btn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);} else {//設(shè)置固定寬度btn->setFixedWidth(20);//設(shè)置拉伸策略使得填充btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);}//設(shè)置焦點(diǎn)策略為無焦點(diǎn),避免單擊后焦點(diǎn)跑到按鈕上btn->setFocusPolicy(Qt::NoFocus);#if 0//設(shè)置圖標(biāo)大小和圖標(biāo)btn->setIconSize(QSize(16, 16));btn->setIcon(icons.at(i));
#elsebtn->setFont(iconFont);btn->setText((QChar)bannerPara.icons.at(i));
#endif//將按鈕加到布局中layout->addWidget(btn);btns << btn;}
}void BannerWidget::initStyle()
{//應(yīng)用樣式表QStringList list;QColor bgColor = bannerPara.bgColor;QString rgba = QString("rgba(%1,%2,%3,%4)").arg(bgColor.red()).arg(bgColor.green()).arg(bgColor.blue()).arg(bannerPara.bgAlpha);list << QString("#bannerWidget{background:%1;border:none;}").arg(rgba);list << QString("QLabel{margin:0px;padding:0px;}");list << QString("QPushButton,QLabel{color:%1;}").arg(bannerPara.textColor.name());list << QString("QPushButton:pressed{color:%1;}").arg(bannerPara.pressColor.name());list << QString("QPushButton{border:none;padding:0px;background:rgba(0,0,0,0);}");this->setStyleSheet(list.join(""));
}void BannerWidget::showInfo(const QString &text)
{this->text = text;if (isRecord) {label->setText(text + " 錄制中...");} else {label->setText(text);}
}void BannerWidget::changeStatus(const QString &objNameSrc, const QString &objNameDst, int icon)
{foreach (QPushButton *btn, btns) {QString objName = btn->objectName();if (objName.endsWith(objNameSrc)) {btn->setObjectName(objName.replace(objNameSrc, objNameDst));btn->setText((QChar)icon);break;}}
}
五、功能特點(diǎn)
5.1 基礎(chǔ)功能
- 支持各種音頻視頻文件格式,比如mp3、wav、mp4、asf、rm、rmvb、mkv等。
- 支持本地?cái)z像頭設(shè)備,可指定分辨率、幀率。
- 支持各種視頻流格式,比如rtp、rtsp、rtmp、http等。
- 本地音視頻文件和網(wǎng)絡(luò)音視頻文件,自動識別文件長度、播放進(jìn)度、音量大小、靜音狀態(tài)等。
- 文件可以指定播放位置、調(diào)節(jié)音量大小、設(shè)置靜音狀態(tài)等。
- 支持倍速播放文件,可選0.5倍、1.0倍、2.5倍、5.0倍等速度,相當(dāng)于慢放和快放。
- 支持開始播放、停止播放、暫停播放、繼續(xù)播放。
- 支持抓拍截圖,可指定文件路徑,可選抓拍完成是否自動顯示預(yù)覽。
- 支持錄像存儲,手動開始錄像、停止錄像,部分內(nèi)核支持暫停錄像后繼續(xù)錄像,跳過不需要錄像的部分。
- 支持無感知切換循環(huán)播放、自動重連等機(jī)制。
- 提供播放成功、播放完成、收到解碼圖片、收到抓拍圖片、視頻尺寸變化、錄像狀態(tài)變化等信號。
- 多線程處理,一個(gè)解碼一個(gè)線程,不卡主界面。
5.2 特色功能
- 同時(shí)支持多種解碼內(nèi)核,包括qmedia內(nèi)核(Qt4/Qt5/Qt6)、ffmpeg內(nèi)核(ffmpeg2/ffmpeg3/ffmpeg4/ffmpeg5)、vlc內(nèi)核(vlc2/vlc3)、mpv內(nèi)核(mpv1/mp2)、??祍dk、easyplayer內(nèi)核等。
- 非常完善的多重基類設(shè)計(jì),新增一種解碼內(nèi)核只需要實(shí)現(xiàn)極少的代碼量,就可以應(yīng)用整套機(jī)制。
- 同時(shí)支持多種畫面顯示策略,自動調(diào)整(原始分辨率小于顯示控件尺寸則按照原始分辨率大小顯示,否則等比例縮放)、等比例縮放(永遠(yuǎn)等比例縮放)、拉伸填充(永遠(yuǎn)拉伸填充)。所有內(nèi)核和所有視頻顯示模式下都支持三種畫面顯示策略。
- 同時(shí)支持多種視頻顯示模式,句柄模式(傳入控件句柄交給對方繪制控制)、繪制模式(回調(diào)拿到數(shù)據(jù)后轉(zhuǎn)成QImage用QPainter繪制)、GPU模式(回調(diào)拿到數(shù)據(jù)后轉(zhuǎn)成yuv用QOpenglWidget繪制)。
- 支持多種硬件加速類型,ffmpeg可選dxva2、d3d11va等,mpv可選auto、dxva2、d3d11va,vlc可選any、dxva2、d3d11va。不同的系統(tǒng)環(huán)境有不同的類型選擇,比如linux系統(tǒng)有vaapi、vdpau,macos系統(tǒng)有videotoolbox。
- 解碼線程和顯示窗體分離,可指定任意解碼內(nèi)核掛載到任意顯示窗體,動態(tài)切換。
- 支持共享解碼線程,默認(rèn)開啟并且自動處理,當(dāng)識別到相同的視頻地址,共享一個(gè)解碼線程,在網(wǎng)絡(luò)視頻環(huán)境中可以大大節(jié)約網(wǎng)絡(luò)流量以及對方設(shè)備的推流壓力。國內(nèi)頂尖視頻廠商均采用此策略。這樣只要拉一路視頻流就可以共享到幾十個(gè)幾百個(gè)通道展示。
- 自動識別視頻旋轉(zhuǎn)角度并繪制,比如手機(jī)上拍攝的視頻一般是旋轉(zhuǎn)了90度的,播放的時(shí)候要自動旋轉(zhuǎn)處理,不然默認(rèn)是倒著的。
- 自動識別視頻流播放過程中分辨率的變化,在視頻控件上自動調(diào)整尺寸。比如攝像機(jī)可以在使用過程中動態(tài)配置分辨率,當(dāng)分辨率改動后對應(yīng)視頻控件也要做出同步反應(yīng)。
- 音視頻文件無感知自動切換循環(huán)播放,不會出現(xiàn)切換期間黑屏等肉眼可見的切換痕跡。
- 視頻控件同時(shí)支持任意解碼內(nèi)核、任意畫面顯示策略、任意視頻顯示模式。
- 視頻控件懸浮條同時(shí)支持句柄、繪制、GPU三種模式,非絕對坐標(biāo)移來移去。
- 本地?cái)z像頭設(shè)備支持指定設(shè)備名稱、分辨率、幀率進(jìn)行播放。
- 錄像文件同時(shí)支持打開的視頻文件、本地?cái)z像頭、網(wǎng)絡(luò)視頻流等。
- 瞬間響應(yīng)打開和關(guān)閉,無論是打開不存在的視頻或者網(wǎng)絡(luò)流,探測設(shè)備是否存在,讀取中的超時(shí)等待,收到關(guān)閉指令立即中斷之前的操作并響應(yīng)。
- 支持打開各種圖片文件,支持本地音視頻文件拖曳播放。
- 視頻控件懸浮條自帶開始和停止錄像切換、聲音靜音切換、抓拍截圖、關(guān)閉視頻等功能。
- 音頻組件支持聲音波形值數(shù)據(jù)解析,可以根據(jù)該值繪制波形曲線和柱狀聲音條,默認(rèn)提供了聲音振幅信號。
- 各組件中極其詳細(xì)的打印信息提示,尤其是報(bào)錯(cuò)信息提示,封裝的統(tǒng)一打印格式。針對現(xiàn)場復(fù)雜的設(shè)備環(huán)境測試極其方便有用,相當(dāng)于精確定位到具體哪個(gè)通道哪個(gè)步驟出錯(cuò)。
- 代碼框架和結(jié)構(gòu)優(yōu)化到最優(yōu),性能強(qiáng)悍,持續(xù)迭代更新升級。
- 源碼支持Qt4、Qt5、Qt6,兼容所有版本。
5.3 視頻控件
- 可動態(tài)添加任意多個(gè)osd標(biāo)簽信息,標(biāo)簽信息包括名字、是否可見、字號大小、文本文字、文本顏色、標(biāo)簽圖片、標(biāo)簽坐標(biāo)、標(biāo)簽格式(文本、日期、時(shí)間、日期時(shí)間、圖片)、標(biāo)簽位置(左上角、左下角、右上角、右下角、居中、自定義坐標(biāo))。
- 可動態(tài)添加任意多個(gè)圖形信息,這個(gè)非常有用,比如人工智能算法解析后的圖形區(qū)域信息直接發(fā)給視頻控件即可。圖形信息支持任意形狀,直接繪制在原始圖片上,采用絕對坐標(biāo)。
- 圖形信息包括名字、邊框大小、邊框顏色、背景顏色、矩形區(qū)域、路徑集合、點(diǎn)坐標(biāo)集合等。
- 每個(gè)圖形信息都可指定三種區(qū)域中的一種或者多種,指定了的都會繪制。
- 內(nèi)置懸浮條控件,懸浮條位置支持頂部、底部、左側(cè)、右側(cè)。
- 懸浮條控件參數(shù)包括邊距、間距、背景透明度、背景顏色、文本顏色、按下顏色、位置、按鈕圖標(biāo)代碼集合、按鈕名稱標(biāo)識集合、按鈕提示信息集合。
- 懸浮條控件一排工具按鈕可自定義,通過結(jié)構(gòu)體參數(shù)設(shè)置,圖標(biāo)可選圖形字體還是自定義圖片。
- 懸浮條按鈕內(nèi)部實(shí)現(xiàn)了錄像切換、抓拍截圖、靜音切換、關(guān)閉視頻等功能,也可以自行在源碼中增加自己對應(yīng)的功能。
- 懸浮條按鈕對應(yīng)實(shí)現(xiàn)了功能的按鈕,有對應(yīng)圖標(biāo)切換處理,比如錄像按鈕按下后會切換到正在錄像中的圖標(biāo),聲音按鈕切換后變成靜音圖標(biāo),再次切換還原。
- 懸浮條按鈕單擊后都用名稱唯一標(biāo)識作為信號發(fā)出,可以自行關(guān)聯(lián)響應(yīng)處理。
- 懸浮條空白區(qū)域可以顯示提示信息,默認(rèn)顯示當(dāng)前視頻分辨率大小,可以增加幀率、碼流大小等信息。
- 視頻控件參數(shù)包括邊框大小、邊框顏色、焦點(diǎn)顏色、背景顏色(默認(rèn)透明)、文字顏色(默認(rèn)全局文字顏色)、填充顏色(視頻外的空白處填充黑色)、背景文字、背景圖片(如果設(shè)置了圖片優(yōu)先取圖片)、是否拷貝圖片、縮放顯示模式(自動調(diào)整、等比例縮放、拉伸填充)、視頻顯示模式(句柄、繪制、GPU)、啟用懸浮條、懸浮條尺寸(橫向?yàn)楦叨?、縱向?yàn)閷挾?#xff09;、懸浮條位置(頂部、底部、左側(cè)、右側(cè))。
5.4 內(nèi)核ffmpeg
- 支持各種音視頻文件、本地?cái)z像頭設(shè)備,各種視頻流網(wǎng)絡(luò)流。
- 支持開始播放、暫停播放、繼續(xù)播放、停止播放、設(shè)置播放進(jìn)度、倍速播放。
- 可設(shè)置音量、靜音切換、抓拍圖片、錄像存儲。
- 自動提取專輯信息比如標(biāo)題、藝術(shù)家、專輯、專輯封面,自動顯示專輯封面。
- 完美支持音視頻同步和倍速播放。
- 解碼策略支持速度優(yōu)先、質(zhì)量優(yōu)先、均衡處理、最快速度。
- 支持手機(jī)視頻旋轉(zhuǎn)角度顯示,比如一般手機(jī)拍攝的視頻是旋轉(zhuǎn)了90度的,解碼顯示的時(shí)候需要重新旋轉(zhuǎn)90度才是正的。
- 自動轉(zhuǎn)換yuv420格式,比如本地?cái)z像頭是yuyv422格式,有些視頻文件是xx格式,統(tǒng)一將非yuv420格式轉(zhuǎn)換,然后再進(jìn)行處理。
- 支持硬解碼dxva2、d3d11va等,性能極高尤其是大分辨率比如4K視頻。
- 視頻響應(yīng)極低延遲0.2s左右,極速響應(yīng)打開視頻流0.5s左右,專門做了優(yōu)化處理。
- 硬解碼和GPU繪制組合,極低CPU占用,比??荡笕A等客戶端更優(yōu)。
- 支持視頻流中的各種音頻格式,AAC、PCM、G.726、G.711A、G.711Mu、G.711ulaw、G.711alaw、MP2L2等都支持,推薦選擇AAC兼容性跨平臺性最好。
- 視頻存儲支持yuv、h264、mp4多種格式,音頻存儲支持pcm、wav、aac多種格式。默認(rèn)視頻mp4格式、音頻aac格式。
- 支持分開存儲音頻視頻文件,也支持合并到一個(gè)mp4文件,默認(rèn)策略是無論何種音視頻文件格式存儲,最終都轉(zhuǎn)成mp4及aac格式,然后合并成音視頻一起的mp4文件。
- 支持本地?cái)z像頭實(shí)時(shí)視頻顯示帶音頻輸入輸出,音視頻錄制合并到一個(gè)mp4文件。
- 支持H264/H265編碼(現(xiàn)在越來越多的監(jiān)控?cái)z像頭是H265視頻流格式)生成視頻文件,內(nèi)部自動識別切換編碼格式。
- 自動識別視頻流動態(tài)分辨率改動,重新打開視頻流。
- 支持用戶信息中包含特殊字符(比如用戶信息中包含+#@等字符)的視頻流播放,內(nèi)置解析轉(zhuǎn)義處理。
- 純qt+ffmpeg解碼,非sdl等第三方繪制播放依賴,gpu繪制采用qopenglwidget,音頻播放采用qaudiooutput。
- 同時(shí)支持ffmpeg2、ffmpeg3、ffmpeg4、ffmpeg5版本,全部做了兼容處理。如果需要支持xp需要選用ffmpeg3及以下。