項目背景是java,前端angular按照java的尿性做設(shè)備驅(qū)動如果沒有底層支持的話直播會是個入坑點诉儒。
直播的方案如果不去說主流直播行業(yè)葡缰,攝像頭只是單獨的功能點的話,基本上都是繞不開ffmpeg的允睹,有window系統(tǒng)直接用ffmpeg.exe拼接命令推流的运准,有使用javacv的。鑒于服務(wù)是多平臺部署缭受,windows胁澳,linux多端運行的,還是考慮一下兼容性采用javacv方案米者。
sdk方式和onvif方式不同點在于云臺控制和預置點操作一個調(diào)用SDK韭畸,一個是采用onvif通信協(xié)議,兩者實現(xiàn)方式不盡相同蔓搞,但是效果大同小異胰丁。
話不多說,開干!
去何狗郑康平臺下載最新的sdk的實例锦庸,文檔寫的比較雜,但是還是能找到對應版本的實現(xiàn)的蒲祈。
先解決sdk調(diào)用動態(tài)庫的問題甘萧,我們先需要一個sdk的實例。
寫一個SdkInstanceUtil的工具類來創(chuàng)建sdk的實例
加載實例需要注意windows加載實例和linux加載實例有區(qū)別梆掸,我們的動態(tài)庫放在配置文件中扬卷,
動態(tài)庫配置完成后,增加一個LoadRsource的類將動態(tài)庫加載酸钦,sdk文檔中有對應的加載方式怪得,這里就不多寫了,這是第一個避坑點卑硫,多讀文檔沒壞處徒恋。(我是踩了幾次的,因為我們是docker部署的拔恰,那個酸爽因谎。。颜懊。财岔。)
還是介紹一下docker里面dockerfile的傻瓜配置方式风皿,就是容器加載動態(tài)庫,不用增加loadResouce這個操作匠璧。
接下來就是調(diào)用sdk提供的接口進行業(yè)務(wù)組裝的過程桐款。
首先我們是兩套sdk,windows和linux版本的夷恍,也就是說我們會有兩套sdk的接口代碼魔眨,但是我們的業(yè)務(wù)可以只寫一套撒,面向接口編程撒酿雪,
我們首先抽象出一套接口遏暴,建一個接口叫SdkProxyService,當當當當,粗線吧:
接下來需要實現(xiàn)一下具體平臺對應的service
然后根據(jù)平臺注入對應的service指黎,
接下來就是我們的業(yè)務(wù)接口了朋凉,再寫一個接口,這個就是我們的業(yè)務(wù)組裝醋安,需要sdk中哪些業(yè)務(wù)組合起來構(gòu)成我們自身的業(yè)務(wù)邏輯杂彭。
具體的實現(xiàn)應該是播放,云臺和預置點操作等等:
sdk的實時播放有提供回調(diào)的方式和不提供回調(diào)的方式吓揪,兩者區(qū)別不大亲怠,基本上都有返回播放句柄的參數(shù),但是問題在于sdk播放時給的流是ps碼流柠辞,前端是無法直接播放的团秽,關(guān)于ps碼流抽流的操作比較復雜,我翻了一篇文檔大概十幾萬字叭首,看自閉了徙垫。
實時播放采用rtsp->javacv->rtmp容器,前端播放rtmp或者http地址放棒。這里需要增加一個rtmp的容器。
推流引包:
真正的坑來了哈己英。
開始進坑间螟,這個坑怎么說呢,rtsp協(xié)議是一種流媒體的協(xié)議损肛,可以遠程查看攝像頭畫面厢破,但是問題是前端瀏覽器么有一款播放器可以播放rtsp的流,有童鞋就說了 治拿,我可以用vlc插件摩泪,vlc可以,但是chrome41以上就不支持了劫谅,ie是可以的见坑,火狐也不行嚷掠,有童鞋又說了我們可以用websocket中轉(zhuǎn)幀,這就是另外的解決方案了荞驴,我們隨后再講不皆,先講javacv的拉流推流的操作。
采用h264轉(zhuǎn)flv的方式直接轉(zhuǎn)碼推熊楼,talk is cheap霹娄,show me the code!
先把錄制器和解碼器構(gòu)建完畢后放入線程開始推畫面
推流線程中有一個錄制器的結(jié)束標識鲫骗,這里的作用主要是用來結(jié)束線程犬耻,之前用的callable這里后來改掉了可以改成runnable,這里的直播采用的是多個用戶看一個,也就是說一個攝像頭只推一路执泰,再來一個人就把redis里面的計數(shù)器+1,當最后一個人關(guān)掉視頻時枕磁,將錄制器里的結(jié)束輸入流置為true,這時候線程就可以結(jié)束了坦胶。
dto.getGrabber().setCloseInputStream(true);
如果是多實例部署的話透典,需要注意訪問實例是否是推流線程所在實例,我們這邊采用的是kafka廣播做的顿苇,當然這種方法比較懶省事峭咒,可以記錄一下實例id去調(diào)對應實例的接口,多實例必然要用redis在記錄當前設(shè)備推流的信息纪岁,避免多個實例同時推一個設(shè)備的現(xiàn)象凑队,比較浪費資源。
sdk可能會出現(xiàn)臨時文件限制的問題幔翰,這個百度一下即可解決漩氨,轉(zhuǎn)碼需要關(guān)注內(nèi)存消耗情況。
再講一下websocket代理轉(zhuǎn)幀的方式遗增,以上方案采用的方式大體流程如下:
rtsp->ffpmeg->rtmp->前端
其中rtmp是一個容器叫惊,websocket轉(zhuǎn)幀的話采用的方式與這個方式大同小異前面兩部分不變,不再使用rtmp容器而是將流推入websocket服務(wù)器做修,前端使用jsmpeg.js將websocket中的幀畫面繪制在canvas中霍狰。
推流方式不變將轉(zhuǎn)碼的方式由flv變?yōu)閙peg1video(敲黑板),推流地址變?yōu)橐粋€websocket服務(wù)器饰及,前端不再使用vedio.js這種播放器啦蔗坯。具體實現(xiàn)方式看各自項目需求。下篇講onvif燎含。