I.はじめに
以前のビデオ監視システムでは、さまざまなユーザーのニーズに応じて、さまざまなビデオ監視カーネルが作成されていました。それらをユニバーサルにするために、ffmpegカーネル、vlcカーネル、mpvカーネル、およびHaikang sdkカーネルがあります。異なるカーネルの機能は切り替えるのに非常に便利です。たとえば、proはDEFINEの変数名を直接変更するため、さまざまなカーネルを同じインターフェイスで使用する必要があるため、見栄えがよく、汎用性は後で特別に調整されますビデオコントロール。このコントロールには、特定のビデオ再生コントロール機能はありません。異なるコアに応じて特定のメソッドを呼び出すことによって実装する必要があります。DahuaSDKまたは他のサードパーティメーカーの契約を後で追加する必要がある場合、この一般的なビデオコントロールを直接適用できます。 、将来的に新しい監視カーネルを追加すると、多くの作業を節約できます。基本的には、カーネル分析を行うだけでよく、残りの一般的なインターフェイスと描画画像は、一般的なビデオコントロールに直接渡されます。
一般的なビデオ制御機能:
- ボーダーサイズを設定できます
- ボーダー色を設定できます
- 2つのOSDラベルを設定できます
- OSDラベルを描画するかどうかを設定できます
- ラベルのテキストまたは画像を設定できます
- OSD位置左上隅+左下隅+右上隅+右下隅を設定できます
- OSDスタイルのテキスト+日付+時刻+日付と時刻+画像を設定できます
- カスタム半透明フローティングフォーム、ボタンの行
- フローティングボタンは、背景色+プレス色を含むカスタマイズされた設定です。
- フローティングボタンがクリックされたことを通知
- ドラッグされたファイルを識別し、URLに通知することができます
- オープンクローズポーズなどのインターフェースを提供する
2.機能
- 1 + 4 + 6 + 8 + 9 + 13 + 16 + 25 + 36 + 64画面切り替えを含む、マルチ画面切り替え、全画面切り替えなどをサポートします。
- alt + Enter全画面をサポートし、escは全画面を終了します。
- カスタム情報ボックス+エラーボックス+問い合わせボックス+右下隅のプロンプトボックス(複数のフォーマットを含む)。
- 17セットのスキンスタイルは自由に変更でき、メニューを含め、すべてのスタイルが統一されています。
- ジンバルダッシュボード上でマウスを動かしてハイライトすると、8つの方向が正確に識別されます。
- 下部の画面のツールバー(画面分割スイッチ+スクリーンショットサウンドおよびその他の設定)が上に移動して強調表示されます。
- ロゴ+中国語のソフトウェア名+英語のソフトウェア名は、構成ファイルで変更できます。
- Baiduマップ、ビューの切り替え、モーショントラック、デバイスの位置、および緯度と経度を取得するためのマウスクリックなどをカプセル化します。
- 画像マップをサポートし、デバイスボタンを画像マップ上で自由にドラッグして、位置情報を自動的に保存できます。
- Baiduマップと画像マップで、ビデオをダブルクリックしてカメラのリアルタイムビデオをプレビューします。
- スタックウィンドウ。各ウィンドウは個別のqwidgetであり、独自のコードを記述するのに便利です。
- 上部マウスの右クリックメニューは、時間の表示と非表示を動的に制御でき、CPU +左上パネル+左下パネル+右上パネル+右下パネルで、デフォルトレイアウトの復元をサポートします。
- ツールバーには、複数の小さなアイコンと閉じるアイコンを配置できます。
- 左側と右側はドラッグして引き伸ばすことができ、幅と高さの位置は自動的に記憶され、再起動後に復元されます。
- カメラノードをダブルクリックすると、ビデオが自動的に再生され、ノードをダブルクリックすると、ビデオが順番に自動的に追加され、次のノードに自動的にスキップされます。親ノードをダブルクリックすると、ノードの下にあるすべてのビデオが自動的に追加されます。
- カメラノードを対応するウィンドウにドラッグしてビデオを再生します。ローカルファイルは直接再生用にサポートされています。
- ビデオフレームはドラッグとスワッピングをサポートし、即座に応答します。
- ノードをダブルクリックしてノードをドラッグし、フォームをドラッグして位置を入れ替えると、url.txtが自動的に更新されます。
- url.txtからのチャンネル動画再生の読み込みをサポートし、最後のチャンネルに対応する動画を自動的に記憶し、ソフトウェアの起動後に自動的に開いて再生します。
- 右下隅の音量バーコントロールは、フォーカスが失われると自動的に非表示になり、音量バーにはミュートアイコンが表示されます。
- Baiduオンラインマップとオフラインマップを統合し、デバイスの対応する場所を追加したり、マップを自動的に生成したり、ズームをサポートしたり、オーバーレイを追加したりできます。
- ビデオをチャンネルウィンドウの外にドラッグすると、ビデオが自動的に削除されます。
- マウスの右ボタンで、現在の+すべてのビデオを削除できます。
- レコーダー管理、カメラ管理、印刷情報を追加、削除、変更、インポート、エクスポートし、再起動せずにすぐに新しいデバイス情報を適用してツリーリストを生成できます。
- マップをproファイルにロードするかどうかを自由に有効にすることができます。
- ビデオ再生用に2種類のカーネルを自由に切り替えることができます。vlc+ ffmpeg、どちらもプロで設定できます。
- 1 + 4 + 9 + 16画面ポーリングを設定でき、ポーリング間隔とポーリングストリームタイプを設定できます。メインインターフェイスの下部にあるツールバーの右側にある[ポーリングの開始]ボタンをクリックし、もう一度クリックしてポーリングを停止します。
- デフォルトでは、マウスポインターは10秒以上操作しないと自動的に非表示になります。
- onvif検索機器をサポートし、任意のonvifカメラをサポートします。これには、Haikang Dahuayu Shitiandi Weiye Huaweiなどが含まれますが、これらに限定されません。
- onvif PTZコントロールをサポートし、PTZカメラを上下左右に移動できます(リセットとフォーカス調整を含む)。
- 同時に、sqlite、mysql、postsqlなどのデータベースもサポートしています。
- ビデオを保存でき、タイミングストレージまたは単一ファイルストレージはオプションで、ストレージインターバルはオプションです。
- ビデオストリームの通信方法をtcp + udpに設定し、ビデオのデコードを速度優先、品質優先、イコライゼーションなどに設定できます。
- ハードデコードタイプの設定、qsv、dxva2、d3d11vaなどのサポートが可能
- デフォルトでは、openglを使用してビデオを描画します。これは、CPUリソースの消費量が非常に少なく、yuyvおよびnv12形式の描画をサポートしています。これは非常に優れています。
- 高度にカスタマイズ可能で、ユーザーはこれに基づいて独自の機能を簡単に導出でき、LinuxおよびMacシステムをサポートします。
3、レンダリング
4、関連サイト
- 国内サイト:https : //gitee.com/feiyangqingyun/QWidgetDemo
- 国際サイト:https : //github.com/feiyangqingyun/QWidgetDemo
- 個人ホームページ:https : //blog.csdn.net/feiyangqingyun
- Zhihuホームページ:https ://www.zhihu.com/people/feiyangqingyun/
- エクスペリエンスアドレス:https : //blog.csdn.net/feiyangqingyun/article/details/97565652
5、コアコード
void VideoWidget::paintEvent(QPaintEvent *)
{
//如果不需要绘制
if (!drawImage) {
return;
}
//qDebug() << TIMEMS << "paintEvent" << objectName();
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing);
//绘制边框
drawBorder(&painter);
if (!image.isNull()) {
//绘制背景图片
drawImg(&painter, image);
//绘制标签
drawOSD(&painter, osd1Visible, osd1FontSize, osd1Text, osd1Color, osd1Image, osd1Format, osd1Position);
drawOSD(&painter, osd2Visible, osd2FontSize, osd2Text, osd2Color, osd2Image, osd2Format, osd2Position);
} else {
//绘制背景
drawBg(&painter);
}
}
void VideoWidget::drawBorder(QPainter *painter)
{
if (borderWidth == 0) {
return;
}
painter->save();
QPen pen;
pen.setWidth(borderWidth);
pen.setColor(hasFocus() ? focusColor : borderColor);
painter->setPen(pen);
painter->drawRect(rect());
painter->restore();
}
void VideoWidget::drawBg(QPainter *painter)
{
painter->save();
//背景图片为空则绘制文字,否则绘制背景图片
if (bgImage.isNull()) {
painter->setFont(this->font());
painter->setPen(palette().foreground().color());
painter->drawText(rect(), Qt::AlignCenter, bgText);
} else {
//居中绘制
int pixX = rect().center().x() - bgImage.width() / 2;
int pixY = rect().center().y() - bgImage.height() / 2;
QPoint point(pixX, pixY);
painter->drawImage(point, bgImage);
}
painter->restore();
}
void VideoWidget::drawImg(QPainter *painter, QImage img)
{
painter->save();
int offset = borderWidth * 1 + 0;
if (fillImage) {
QRect rect(offset / 2, offset / 2, width() - offset, height() - offset);
painter->drawImage(rect, img);
} else {
//按照比例自动居中绘制
img = img.scaled(width() - offset, height() - offset, Qt::KeepAspectRatio);
int pixX = rect().center().x() - img.width() / 2;
int pixY = rect().center().y() - img.height() / 2;
QPoint point(pixX, pixY);
painter->drawImage(point, img);
}
painter->restore();
}
void VideoWidget::drawOSD(QPainter *painter,
bool osdVisible,
int osdFontSize,
const QString &osdText,
const QColor &osdColor,
const QImage &osdImage,
const VideoWidget::OSDFormat &osdFormat,
const VideoWidget::OSDPosition &osdPosition)
{
if (!osdVisible) {
return;
}
painter->save();
//标签位置尽量偏移多一点避免遮挡
QRect osdRect(rect().x() + (borderWidth * 2), rect().y() + (borderWidth * 2), width() - (borderWidth * 5), height() - (borderWidth * 5));
int flag = Qt::AlignLeft | Qt::AlignTop;
QPoint point = QPoint(osdRect.x(), osdRect.y());
if (osdPosition == OSDPosition_Left_Top) {
flag = Qt::AlignLeft | Qt::AlignTop;
point = QPoint(osdRect.x(), osdRect.y());
} else if (osdPosition == OSDPosition_Left_Bottom) {
flag = Qt::AlignLeft | Qt::AlignBottom;
point = QPoint(osdRect.x(), osdRect.height() - osdImage.height());
} else if (osdPosition == OSDPosition_Right_Top) {
flag = Qt::AlignRight | Qt::AlignTop;
point = QPoint(osdRect.width() - osdImage.width(), osdRect.y());
} else if (osdPosition == OSDPosition_Right_Bottom) {
flag = Qt::AlignRight | Qt::AlignBottom;
point = QPoint(osdRect.width() - osdImage.width(), osdRect.height() - osdImage.height());
}
if (osdFormat == OSDFormat_Image) {
painter->drawImage(point, osdImage);
} else {
QDateTime now = QDateTime::currentDateTime();
QString text = osdText;
if (osdFormat == OSDFormat_Date) {
text = now.toString("yyyy-MM-dd");
} else if (osdFormat == OSDFormat_Time) {
text = now.toString("HH:mm:ss");
} else if (osdFormat == OSDFormat_DateTime) {
text = now.toString("yyyy-MM-dd HH:mm:ss");
}
//设置颜色及字号
QFont font;
font.setPixelSize(osdFontSize);
painter->setPen(osdColor);
painter->setFont(font);
painter->drawText(osdRect, flag, text);
}
painter->restore();
}