onvif客戶端
前言
做開發有8年時間了,ffmpeg和onvif與我是特別有緣的了(說著玩的,我更認為是因為他們確實強大^_^
)。 ffmpeg在畢業設計時就有用到,5年後做windows、linux播放庫時又有用到,於是又重新研究!!! onvif是我在畢業第二年的時候,有從0開始寫過一個onvif服務端NVT,沒想到6年後,項目中的客戶端又需要用到它!!!其實本來不想開發它的,但是因為客戶端依賴的onvif部分是別人的庫,我們需要onvif抓圖功能,結果對方沒時間做,也不願意把代碼開放給我們,我特郁悶,這個又沒什麽技術含量,沒必要當個寶藏著吧! 於是花了一周時間開發了自己的onvif客戶端(這裏不是從0開發,而是基於現有的開源onvif客戶端開發的)。
onvif客戶端開發過程
開發這類東西一般有兩條路可選擇,要麽從0開始編碼,要麽基於現有的開源代碼進行改進,完善。我通常會先嘗試後者,沒有合適的開源代碼可參考時,才會從0開始編碼,沒必要發明輪子。下面記錄下我的開發過程。
首先,用搜索引擎搜索onvif客戶端,去github或者gitlab上搜索onvif客戶端,從找到的結果中刷選出一些可能合適的,我最開始得出以下可能:
- onvif-qt-server-client
- qt-onvif-client
- clientlib
- OnvifClient
- ONVIF Device Manager
我主要的過濾條件包括:
- 我們項目是C++的,我希望是onvif客戶端庫也是c/c++開發的
- 我希望該onvif庫的最後維護時間盡可能新,因為onvif有很多版本,不同版本的wsdl生成的最終文件包含的功能有很大不同
- 能夠在1天內編譯通過該開源的代碼,因為很多開源的項目不夠完善,別人很難很快的將其用起來
- 代碼寫的盡量的標準、規範,換句話說,要寫的好看
經過以上幾個過濾實施後,我選擇了 ONVIF Device Manager,它是c++開發的,而且和最新的onvif幾乎同步,也是一次就編譯通過了,通過簡單的代碼閱讀,覺得代碼寫的挺漂亮的^_^
進一步了解代碼後,發現ONVIF Device Manager所提供的開源部分只是包含了onvif客戶端的開發框架,很多功能都沒有完全實現,但是很容易的進行完善,這得益於它漂亮的代碼編寫!這裏簡單的描述下我二次開發的過程,目錄結構圖如下:
onvif客戶端功能的核心部分都是在onvifgen目錄裏面實現的(當然,很多都沒寫完,但是很容易補充全),它對應了onvifcpplib工程,生成onvifclient.lib靜態庫
example\client\onvifclientwin32裏面包含了一個onvifclient.lib靜態庫對應的測試demo
分析出以上兩部分之後,就可以得出二次開發的方案了,我采用的修改example\client\onvifclientwin32,將它變成自己onvif客戶端對外的導出層,將編譯生成exe改成生成dll,然後根據需求完善onvifcpplib。
舉例說明1:onvif搜索實現
搜索的實現是通過OnvifClientSearch類來完成的,該類已定義,但是功能需要自己補充,對應的頭文件onvifclientsearch.hpp,它內部是通過wsddProxy代理來實現搜索的,該代理封裝了soap,代理部分的大部分功能這個開源庫已經實現了,也就是說學會怎麽使用該類即可。
舉例說明2:onvif ptz實現
ptz的實現是通過OnvifClientPTZ類來完成的,該類已定義,但是功能需要自己補充,對應的頭文件onvifclientptz.hpp,它內部是通過PTZBindingProxy代理來實現ptz控制的,該代理封裝了soap,代理部分的大部分功能這個開源庫已經實現了,也就是說學會怎麽使用該類即可。因此,好消息是onvif ptz協議部分基本已經實現,我們要做的就是根據PTZBindingProxy類實現一些ptz方法,然後補充到OnvifClientPTZ類中。
舉例說明3:onvif 抓圖實現
抓圖的實現是通過OnvifClientMedia類來完成的,該類已定義,但是功能需要自己補充,對應的頭文件onvifclientmedia.hpp,它內部是通過MediaBindingProxy代理來實現ptz控制的,該代理封裝了soap,代理部分的大部分功能這個開源庫已經實現了,也就是說學會怎麽使用該類即可。我們主要需要通過onvif協議獲取抓圖uri,然後通過http去這個uri取抓圖的數據即可。參考實現如下:
···
inline int OnvifClientMedia::GetSnapshotUri(_trt__GetSnapshotUriResponse &SnapshotUriResponse,string profileToken)
{
string strUrl;
string strUser;
string strPass;
if (m_Device.GetUserPasswd(strUser, strPass) == false
|| m_Device.GetMediaUrl(strUrl) == false)
{
return SOAP_ERR;
}
mediaProxy.soap_endpoint = strUrl.c_str();
soap_wsse_add_Security(&mediaProxy);
soap_wsse_add_UsernameTokenDigest(&mediaProxy, "Id", strUser.c_str() , strPass.c_str());
_trt__GetSnapshotUri SnapshotUriReq;
SnapshotUriReq.ProfileToken = profileToken;
return mediaProxy.GetSnapshotUri(&SnapshotUriReq, &SnapshotUriResponse);
}
···
總結
我的onvif客戶端的實現沒有從0開始,而是采用基於ONVIF Device Manager二次開發實現的,該開源的代碼寫的非常漂亮,且onvif的功能也實現的非常全,同時,要擴展自己的功能的操作也是那固定的幾步,因此我認為用它作為自己onvif客戶端實現是非常適合的。
onvif客戶端