純Qt手撕gb28181協議/gb28181協議服務端/gb28181協議設備端/gb28181設備模擬器/gb28181虛擬監控設備

一、前言說明

搞完onvif設備模擬器,總想著把28181設備模擬也實現,因為之前已經花了大力氣把28181平臺軟件端實現了,為了實現這個組件,頭發掉了一大把,專門把國標文檔看了好幾遍,逐行閱讀,針對需要實現的交互協議,逐一實現,然后在N多實際現場測試,給最終用戶使用,不斷反饋迭代修改,以滿足更多的實際需求,比如有些廠家設備居然沒有ssrc,有些嚴格要求設備IP地址認證,有些只支持tcp被動方式,林林種種N多實際的特殊需求,都不斷調整以便適應,目前已經適配了市面上主流的設備,也有些非主流的也適配了,總之,能考慮到的都考慮了。

既然都已經熟悉了28181協議,那設備端的28181程序實現起來,輕車熟路,相對來說要簡單一些,因為設備模擬要實現的功能不多,能夠主動連接sip服務器,能夠應答設備信息和狀態,心跳保活,視頻點播,主要就這幾個,只不過sip通信鏈路可以是udp或者tcp,視頻點播可以支持udp、tcp主動、tcp被動三種方式。整個實現過程還是沒有碰到太多的難題,畢竟之前就已經把所有可能的坑都趟過去了。

二、效果圖

在這里插入圖片描述

三、相關地址

  1. 國內站點:https://gitee.com/feiyangqingyun
  2. 國際站點:https://github.com/feiyangqingyun
  3. 個人作品:https://blog.csdn.net/feiyangqingyun/article/details/97565652
  4. 文件地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取碼:01jf 文件名:bin_video_simulate。

四、功能特點

  1. 標準onvif協議,支持設備搜索、獲取參數、快照抓圖等。
  2. 支持264/265/aac等標準視音頻協議傳輸。
  3. 支持多路批量onvif設備模擬,每一路都獨立的端口。
  4. 支持本地攝像頭采集轉成onvif,可選擇不同的設備、分辨率、幀率等參數。
  5. 支持本地桌面采集轉成onvif,可選擇不同的屏幕、分辨率、幀率等參數。
  6. 支持各種視頻文件和視頻流轉成onvif,可重新設置編碼轉換以及分辨率轉換。
  7. 支持4K、8K等高清分辨率,不限制分辨率,非264/265會自動轉碼推流。
  8. 每一路都可以設置統一或者獨立的用戶驗證信息,為空則表示不驗證。
  9. 可以把任意內容接入到NVR以及視頻監控系統,方便保存錄像文件,以便回放可查。
  10. 也可作為壓力測試工具,比如模擬幾千路onvif設備,讓集成平臺軟件做接入壓力測試。
  11. 推出去的流不僅有rtsp格式,還支持rtmp、http、flv、ws-flv、webrtc等方式訪問,可以直接網頁查看。
  12. 在管理工具上可以看到每一路的推流狀況以及分辨率信息,非常直觀。
  13. 支持自動重連拉流,重連推流,保證7乘以24小時穩定運行。
  14. 可設置開機自啟動運行和后臺運行,不顯示在任務欄,作為后臺服務運行。
  15. 可批量添加文件、添加目錄,自動將目錄下的所有文件添加到模擬器。
  16. 多功能添加地址面板,可以選擇本地設備和監控設備,本地設備會自動識別攝像頭設備和桌面設備,監控設備可以選擇不同廠家,自動填充對應rtsp格式,填入用戶信息即可,可以批量遞增添加監控設備。
  17. 可無縫上傳到市面上所有的onvif協議設備,包括海康、大華、宇視、華為、天地偉業等,也支持ONVIF Device Manager國際onvif工具。
  18. 支持gb28181設備模擬,具備設備注冊、設備注銷、設備心跳、設備信息、設備配置、設備狀態應答等。
  19. 支持模擬報警和位置上報等,方便平臺側顯示對應設備的實時位置。
  20. 支持一鍵添加批量模擬28181設備,實時顯示已注冊和已注銷狀態。
  21. 支持將本地桌面、本地攝像頭、任意視頻文件、視頻流文件、手機攝像頭等轉換成28181設備,添加到NVR或者國標軟件平臺。
  22. sip協議同時支持udp和tcp兩種通信方式,視頻點播同時支持udp/tcp主動/tcp被動三種方式,涵蓋所有可能的場景需求。
  23. 無論是onvif設備模擬組件還是28181設備模擬組件,全部原創底層協議解析,純Qt實現,跨任意平臺。
  24. 代碼結構框架非常清晰,注釋詳細,代碼精簡不繁瑣,非常易于學習和移植,可以很容易拓展其他接口需求。
  25. 支持Qt4/Qt5/Qt6以及后續所有版本、所有編譯器、所有開發環境。
  26. 支持windows、linux、mac、國產OS、嵌入式linux、RK3588、樹莓派、香橙派等系統。

五、相關代碼

#include "gb28181devicebody.h"int GB28181DeviceBody::idlen = 5;
QString GB28181DeviceBody::getXml(const QString &type, const QStringList &body)
{QStringList list;list << QString("<?xml version=\"1.0\" encoding=\"GB2312\"?>");list << QString("<%1>").arg(type);list << body;list << QString("</%1>").arg(type);return list.join("\r\n");
}QStringList GB28181DeviceBody::getCommonXml(const QString &cmdType, const QString &deviceId, quint64 xmlSN)
{QStringList list;list << QString("  <CmdType>%1</CmdType>").arg(cmdType);list << QString("  <SN>%1</SN>").arg(xmlSN);list << QString("  <DeviceID>%1</DeviceID>").arg(deviceId);return list;
}QString GB28181DeviceBody::getResponseXml(const QString &cmdType, const QString &deviceId, quint64 xmlSN, const QStringList &body)
{QStringList list = GB28181DeviceBody::getCommonXml(cmdType, deviceId, xmlSN);list << "  <Result>OK</Result>";list << body;return GB28181DeviceBody::getXml("Response", list);
}QString GB28181DeviceBody::getNotifyXml(const QString &cmdType, const QString &deviceId, quint64 xmlSN, const QStringList &body)
{QStringList list = GB28181DeviceBody::getCommonXml(cmdType, deviceId, xmlSN);list << body;return GB28181DeviceBody::getXml("Notify", list);
}QString GB28181DeviceBody::getKeepalive(GB28181DevicePara device, quint64 &xmlSN)
{QStringList list;list << QString("  <Status>OK</Status>");return GB28181DeviceBody::getNotifyXml("Keepalive", device.deviceId, xmlSN++, list);
}QString GB28181DeviceBody::getAlarm(GB28181DevicePara device, quint64 &xmlSN, int alarmPriority, int alarmMethod, int alarmType)
{QStringList list;list << QString("  <AlarmPriority>%1</AlarmPriority>").arg(alarmPriority);list << QString("  <AlarmMethod>%1</AlarmMethod>").arg(alarmMethod);list << QString("  <AlarmTime>%1</AlarmTime>").arg(SIPTIME);list << QString("  <Info>");list << QString("    <AlarmType>%1</AlarmType>").arg(alarmType);list << QString("  <Info>");return GB28181DeviceBody::getNotifyXml("Alarm", device.channelId, xmlSN++, list);
}QString GB28181DeviceBody::getMobilePosition(GB28181DevicePara device, quint64 &xmlSN, double longitude, double latitude, double altitude)
{QStringList list;list << QString("  <Time>%1</Time>").arg(SIPTIME);list << QString("  <Longitude>%1</Longitude>").arg(longitude);list << QString("  <Latitude>%1</Latitude>").arg(latitude);list << QString("  <Altitude>%1</Altitude>").arg(altitude);list << QString("  <Speed>%1</Speed>").arg(100);list << QString("  <Direction>%1</Direction>").arg(180);return GB28181DeviceBody::getNotifyXml("MobilePosition", device.channelId, xmlSN++, list);
}QString GB28181DeviceBody::getDeviceInfo(GB28181DevicePara device, quint64 xmlSN)
{QStringList list;list << QString("  <DeviceName>%1-%2</DeviceName>").arg("TX-Camera").arg(device.deviceId.right(idlen));list << QString("  <Manufacturer>%1</Manufacturer>").arg("TaiXue");list << QString("  <Model>%1</Model>").arg("TX-Camera-001");list << QString("  <Firmware>%1</Firmware>").arg("V20250808");list << QString("  <Channel>%1</Channel>").arg(1);return GB28181DeviceBody::getResponseXml("DeviceInfo", device.deviceId, xmlSN, list);
}QString GB28181DeviceBody::getDeviceStatus(GB28181DevicePara device, quint64 xmlSN)
{QStringList list;list << QString("  <Online>%1</Online>").arg("ONLINE");list << QString("  <Status>%1</Status>").arg("OK");list << QString("  <DeviceTime>%1</DeviceTime>").arg(SIPTIME);list << QString("  <Alarmstatus Num=\"%1\"></Alarmstatus>").arg(0);list << QString("  <Encode>%1</Encode>").arg("ON");list << QString("  <Record>%1</Record>").arg("OFF");return GB28181DeviceBody::getResponseXml("DeviceStatus", device.deviceId, xmlSN, list);
}QString GB28181DeviceBody::getCatalog(GB28181DevicePara device, quint64 xmlSN)
{QStringList list;list << QString("  <SumNum>%1</SumNum>").arg(1);list << QString("  <DeviceList Num=\"%1\">").arg("1");list << QString("  <Item>");list << QString("    <DeviceID>%1</DeviceID>").arg(device.channelId);list << QString("    <Name>%1-%2</Name>").arg("TX-Channel").arg(device.channelId.right(idlen));list << QString("    <Manufacturer>%1</Manufacturer>").arg("TaiXue");list << QString("    <Model>%1</Model>").arg("TX-Camera-001");list << QString("    <Owner>%1</Owner>").arg("Owner");list << QString("    <CivilCode>%1</CivilCode>").arg(device.serverRealm);list << QString("    <Address>%1</Address>").arg("Address");list << QString("    <Parental>%1</Parental>").arg(0);list << QString("    <ParentID>%1</ParentID>").arg(device.deviceId);list << QString("    <SafetyWay>%1</SafetyWay>").arg("0");list << QString("    <RegisterWay>%1</RegisterWay>").arg("1");list << QString("    <Secrecy>%1</Secrecy>").arg("0");list << QString("    <Status>%1</Status>").arg("ON");list << QString("  </Item>");list << QString("  </DeviceList>");return GB28181DeviceBody::getResponseXml("Catalog", device.deviceId, xmlSN, list);
}QString GB28181DeviceBody::getConfigDownload(GB28181DevicePara device, quint64 xmlSN)
{QStringList list;list << QString("  <BasicParam>");list << QString("    <Name>%1-%2</Name>").arg("TX-Camera").arg(device.deviceId.right(idlen));list << QString("    <DeviceID>%1</DeviceID>").arg(device.deviceId);list << QString("    <SIPServerID>%1</SIPServerID>").arg(device.serverId);list << QString("    <SIPServerIP>%1</SIPServerIP>").arg(device.serverIp);list << QString("    <SIPServerPort>%1</SIPServerPort>").arg(device.serverPort);list << QString("    <DomainName>%1</DomainName>").arg(device.serverRealm);list << QString("    <Expiration>%1</Expiration>").arg(device.registInterval);list << QString("    <Password>%1</Password>").arg(device.serverPwd);list << QString("    <HeartBeatInterval>%1</HeartBeatInterval>").arg(device.heartInterval);list << QString("    <HeartBeatCount>%1</HeartBeatCount>").arg(device.heartTimeout);list << QString("    <PositionCapability>%1</PositionCapability>").arg(0);list << QString("  </BasicParam>");return GB28181DeviceBody::getResponseXml("ConfigDownload", device.deviceId, xmlSN, list);
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95738.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95738.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95738.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【滲透實戰】無下載器環境(curl/wget)下玩轉 Metasploit 自動利用

1. 背景與問題場景 在滲透測試或漏洞利用中&#xff0c;Metasploit&#xff08;MSF&#xff09;是業界最常用的框架之一。 其許多 RCE&#xff08;遠程代碼執行&#xff09;模塊在落地 payload&#xff08;如 Meterpreter 或反彈 shell&#xff09;時&#xff0c;采用了 CMD St…

jd-hotkey探測熱點key

對任意突發性的無法預先感知的熱點數據&#xff0c;包括并不限于熱點數據&#xff08;如突發大量請求同一個商品&#xff09;、熱用戶&#xff08;如惡意爬蟲刷子&#xff09;、熱接口&#xff08;突發海量請求同一個接口&#xff09;等&#xff0c;進行毫秒級精準探測到。然后…

C#WPF實戰出真汁07--【系統設置】--菜品類型設置

1、菜品設置介紹 菜品設置跟餐桌設置的功能目的是相同的&#xff0c;包括了新增&#xff0c;刪除&#xff0c;編輯&#xff0c;分頁&#xff0c;查詢&#xff0c;重置&#xff0c;全選&#xff0c;全消&#xff0c;列表功能&#xff0c;實現流程也是布局設計&#xff0c;后臺邏…

aave v3 存款與借款利息的計算方式

本文只涉及到利率計算的數學原理&#xff0c;不作源碼解析:存款首先我們假設小明在aave里面存了10000usdt&#xff0c;存的時候年化收益率是5%,那么半年后其存款的利息是多少呢?常規的計算方式如下:利息10000*5%*(存款的時長/一年的時長)這么做有什么問題呢&#xff1f;假設現…

Windows MCP.Net:基于.NET的Windows桌面自動化MCP服務器深度解析

&#x1f4cb; 目錄 項目概述 技術架構深度解析 核心功能模塊詳解 代碼實現分析 使用場景與實戰案例 性能優化與最佳實踐 擴展開發指南 總結與展望 項目概述 什么是Windows-MCP.Net&#xff1f; Windows MCP.Net是一個基于.NET 10.0開發的Windows桌面自動化MCP&…

Boost.Asio學習(7):Boost.Beast實現簡易http服務器

namespace beast boost::beast;beast::flat_buffer是一個用于 Boost.Asio 和 Boost.Beast 網絡讀寫的緩沖區實現。專為 一次性順序讀取 / 消費 場景設計&#xff0c;比 std::string 或 std::vector 高效&#xff0c;因為它是扁平內存結構&#xff08;contiguous memory&#x…

深入解析JVM內存區域劃分:從理論到實踐

Java虛擬機&#xff08;JVM&#xff09;是Java程序運行的核心環境&#xff0c;它負責管理內存分配、垃圾回收、字節碼執行等關鍵任務。理解JVM的內存區域劃分&#xff0c;對于優化Java應用性能、排查內存問題&#xff08;如OutOfMemoryError、StackOverflowError&#xff09;至…

滑窗|貪心|?滾動數組

lc17.08pair按身高升序、相同時體重降序排序結果是找體重序列的最長遞增子序列長度核心&#xff1a;轉化為二維最長遞增子序列問題求解vector<int> dp;for (auto& p : hw) {int w p.second;auto it lower_bound(dp.begin(), dp.end(), w);if (it dp.end()) {dp.pu…

深入理解數據庫架構:從原理到實踐的完整指南

一、數據庫存儲架構的多維度分類體系 1.1 基于數據組織方式的存儲架構分類 數據庫的存儲架構從根本上決定了其性能特征、適用場景和擴展能力。理解不同的數據組織方式是選擇合適數據庫技術的基礎&#xff0c;這種分類不僅反映了技術實現的差異&#xff0c;更體現了對不同業務需…

體彩排列三第2025218期號碼分析

大家好&#xff0c;本人蔡楚門來此平臺分享一下本期得經驗和思路&#xff0c;希望能夠給大家帶來好的運氣和靈感&#xff01;體彩排列三第2025218期號碼分析&#xff0c;大小號碼數字分析&#xff0c;上期開出全小號碼最多&#xff0c;最近兩期的開獎號碼全部都是全小號碼最多&…

java設計模式之迪米特法則介紹與說明

一、核心概念與目標 基本定義 迪米特法則的核心思想是&#xff1a;一個對象應該對其他對象盡可能少地了解&#xff0c;僅與直接關聯的對象&#xff08;即“朋友”&#xff09;通信&#xff0c;避免與“陌生人”產生直接交互。 直接朋友&#xff1a;包括當前對象的成員變量、方法…

2024-2025華為ICT大賽中國區 實踐賽昇騰AI賽道(高職組)全國總決賽 理論部分真題+解析

Part 1 昇騰AI全棧系統模塊(共6題)&#xff1a;1、許多計算芯片可以設計作為人工智能的計算芯片&#xff0c;但不同的芯片計算性能不同&#xff0c;昇騰計算芯片是一種()芯片。(單選題)A.CPU B.GPU C. NPU D.TPU正確答案&#xff1a;C解析&#xff1a;A項CPU中央處理器的架…

網絡安全和基礎設施安全局 (CISA) 表示微分段不再是可選的

網絡安全和基礎設施安全局 (CISA) 最近發布了一系列指導文件中的第一份&#xff0c;旨在幫助聯邦機構實施微分段&#xff0c;作為其零信任架構 (ZTA) 戰略的一部分&#xff0c;以遵守2022 年白宮的授權。 該文件《零信任中的微分段&#xff0c;第一部分&#xff1a;介紹和規劃…

Spring Boot SseEmitter 重復請求問題深度分析與解決方案

1. 前言 在使用 Spring Boot 開發流式接口(Server-Sent Events)時,我們遇到了一個令人困惑的問題:每次 SseEmitter 完成后,都會觸發第二次請求,導致重復請求檢測機制誤報。本文將詳細記錄問題的發現、分析過程以及最終的解決方案。 2. 系統架構背景 2.1 請求處理架構 …

心路歷程-三個了解敲開linux的大門

學習前都愛嘮叨一番&#xff1a; 了解一下&#xff1a;互聯網的發展是離不開服務器的&#xff0c;而服務器的系統主流的還是Linux&#xff1b;這個是有數據進行支撐的&#xff1b;這個只是作為了解而已&#xff0c;我們并不買課&#xff0c;也不做什么買賣的行為&#xff0c;僅…

關于“雙指針法“的總結

筆者這些天終于達成了只狼的全成就&#xff0c;甚是歡喜。然而樂極生悲&#xff0c;最近做了些算法題&#xff0c;竟沒有一道靠自己做出來。感覺算法題常常用到“雙指針法”呢……為什么到現在我還是做不出來這些算法題……今天就來試著總結一下它的使用場景吧。快慢指針法又名…

基于51單片機的智能吊燈

基于 51 單片機的智能吊燈設計與實現論文簡綱一、引言1.1 研究背景與意義闡述傳統照明設備在節能性、智能化方面的不足&#xff0c;結合智能家居產業發展趨勢&#xff0c;說明設計基于 51 單片機的智能吊燈對提升生活便利性、降低能耗的現實意義。1.2 國內外研究現狀簡要介紹當…

CF每日三題(1500-1700)

1792C 逆向思維1036D 前綴和尺取1598D 組合數學取三元組 將二元組放在坐標系中更好找到規律 1792C 思維 1500 參考題解 正難則反 注意是對一個排列進行操作&#xff0c;最后還原成1,2,…,n 每次選兩個數字很難想&#xff0c;反著想就是把1-n的排列變成所給數組的逆操作&#x…

Boost搜索引擎項目(詳細思路版)

目錄 項目相關背景 搜索引擎原理技術棧和項目環境 導入數據到自己的本地 數據去標簽與數據清洗模塊 Enumfile(src_path, &file_list)遞歸式寫入 Parsehtml(file_list, &results)去標簽 bool Parsetitle(const string& file, string* title)拆分標題 bool Pa…

AI產品經理面試寶典第69天:大模型穩定性評估與AI倫理挑戰面試題全解析

1. AI倫理與技術挑戰 1.1 問:你認為AI的最大挑戰是什么? 答:AI面臨的最大挑戰是算法偏見與模型黑箱問題。具體表現為: 數據偏見放大:訓練數據中隱含的性別、種族等偏見會被模型繼承,如招聘算法中的性別歧視案例 決策透明性缺失:深度學習模型的可解釋性不足,醫療診斷場…