流媒体服务器、海康威视大华摄像头实现视频监控、直播解决方案

编程

  随着互联网+物联网进程的加快,视频监控应用领域变得越来越广泛,其中海康威视 大华等品牌的摄像头频繁出现在视野中。由于去年也实现过智慧工地项目上的视频监控方案,加上当今直播趋势不减。现在总结一下:

缘由:是1对N 点对多的直播方式, 一般都是采用服务器转发,所以此处不考虑WebRTC这种端对端的方式,WebRTC将在下一篇文章中讲解下实现思路。

前提:需要海康威视或大华的摄像头,大华摄像头清晰度 品质较好,但相对于海康的摄像头较贵,所以海康威视的摄像头更受口袋欢迎。

一.自建流媒体服务器

  第一种方式就是自建流媒体服务器,然后自己实现采集推流 到服务器 拉流到客户端播放。先看一张图:

  1. 先客户端软件或设备采集视频流和语音流,或者是摄像头硬件采集的画面流等(如何采集就属于硬件相关的问题了,此处不讨论)
  2. 然后通过推流的方式推到流媒体服务器,推流协议可以使用RTMP RMSP,这2种都是基于tcp的 不会丢包。但是很容易造成高延迟(具体的看服务器 网络 是否做CDN来支撑)。

    1//可指定h264或h265编码,可以把h265编码看成是h264编码的升级版,在码率 体积 清晰度 移动补偿上更友好些

    2//大体结构为:rtsp://摄像头用户名:密码@地址:端口 服务器上地址参数...

    3 rtsp://admin:yjt_jiankong@192.168.0.60:554/h264/ch1/main/av_stream

    4 rtsp://admin:yjt_jiankong@192.168.0.60:554/Streaming/Channels/101?transportmode=unicast

    以上方式只是实现了流推送到了服务器,并没有指定它播放地址以及播放的转码。因此我们可以考虑使用ffmpeg,这是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。也就是使用ffmpeg不光可以本地采集流还可以指定推送到那一台服务器上和它的播放地址等等;

    1//ffmpeg -re -i表示使用的协议和协议的参数,具体的参数意义请百度

    2//接着是和上面一样的推流,这里使用的是rtsp,建议用rtmp,本帅在使用中感觉rtmp兼容性更好 web前端使用rtmp更方便。比如前端用Flash插件。或者Video标签等等。

    3//然后是基于tcp 转码 播放的地址,比如播放地址是:rtsp://117.250.250.250/Cameratest

    4 ffmpeg -re -i rtsp://admin:yjt_jiankong@192.168.0.60:554/h264/ch1/main/av_stream -rtsp_transport tcp -vcodec h264 -f rtsp rtsp://localhost/test

    5 ffmpeg -i rtsp://admin:yjt_jiankong@192.168.0.60:554/h264/ch1/main/av_stream -rtsp_transport tcp -vcodec h264 -f rtsp rtsp://117.250.250.250/Cameratest

     注意播放地址前指定播放协议,比如rtsp rtsp://117.250.250.250/Cameratest。如果是rtmp那么最后就应该是:rtmp rtmp://117........................

  3. 流媒体服务器做一些编码转码处理等将流分发给各个客户端,进而进行拉流播放。那么问题来了  如何实现流媒体服务器呢?如何架设???
  4. 架设上我们可以使用nginx rtmp-module模块来架设,架设好后就可以使用rtmp推流给它。还可以用上面第2点中的ffmpeg命令写一个bat脚本来测试摄像头和架设的流媒体。
  5. PC端播放使用rtmp Flash来进行播放(H5中的Video标签了解一下),移动端播放使用HLS m3u8 rtmp来进行播放(具体播放方式视项目框架情况而定)。看网上有人还使用flv + http stream 进行播放的。
  6. 后期出现了并发 播放量增多的压力可以把nginx做分层(接入层+交换层),或者是转发一下做负载均衡,或者CDN来支撑。前期如果考虑到后期会使用CDN也可以直接跳过nginx 一开始用cdn的直播服务。

二.接入第三方平台

  在之前的项目中是购买了海康威视的摄像头,所以为了方便快捷的开发,是接入了第三方平台,由第三方平台进行管理和转发。大体流程是往第三方平台注册摄像头信息(序列号 验证码),然后流直接走第三方平台,自己服务端只需要获取三方平台的API接口便能得知播放地址 直接客户端播放。使用的是萤石云。

 

 

 

   我们可以在自己的项目中往萤石云注册摄像头信息(也就是调用萤石云接口 往萤石云写一条数据),然后在需要用的地方获取萤石云API接口播放地址。完全不用管流的处理(得充值)。

   提供一份对萤石云请求封装的类(C#代码):  

  1using Newtonsoft.Json;

2using System;

3using System.Collections.Generic;

4using System.Linq;

5using System.Net.Http;

6using System.Net.Http.Headers;

7using System.Text;

8using System.Threading.Tasks;

9using YJT.Common;

10

11/*20190819 by suzong */

12namespace YJT.Wisdom.Api.lib

13{

14///<summary>

15/// 萤石云请求封装

16///</summary>

17publicclass YsClient

18 {

19privatestaticreadonlystring requestUrl = "https://open.ys7.com/";

20privatestaticreadonlystring appKey = "";//官网注册获得

21privatestaticreadonlystring appSecret = "";//官网注册获得

22

23///<summary>

24/// 获得token

25///</summary>

26///<returns>{code:200,data:{accessToken:"",expireTime:精确到毫秒}}</returns>

27publicstaticasync Task<string> GetToken()

28 {

29string key = ConfigHelper.GetSetting("CacheKey:YsToken") ?? "YsAccessToken";

30string tokenStr = MemoryCacheHelper.Get(key)?.ToString();

31if (string.IsNullOrEmpty(tokenStr))

32 {

33string str = await HttpHelper.HttpPostAsync($"{requestUrl}api/lapp/token/get?appKey={appKey}&appSecret={appSecret}");

34 YsResult result = JsonConvert.DeserializeObject<YsResult>(str);

35//缓存token 缓存时间为5天

36 tokenStr = result?.data?.accessToken;

37 MemoryCacheHelper.Set(key, tokenStr, TimeSpan.FromDays(5));

38 }

39return tokenStr;

40 }

41

42///<summary>

43/// 添加设备

44///</summary>

45///<param name="deviceSerial">设备序列号</param>

46///<param name="validateCode">设备验证码</param>

47///<returns></returns>

48publicstaticasync Task<YsResult> SaveDevice(string deviceSerial, string validateCode)

49 {

50if (string.IsNullOrEmpty(deviceSerial) || string.IsNullOrEmpty(validateCode))

51returnnew YsResult() { code = "-1", msg = "缺少验证码或序列号" };

52

53string str = await HttpHelper.HttpPostAsync($"{requestUrl}api/lapp/device/add?accessToken={GetToken().Result}&deviceSerial={deviceSerial.ToUpper()}&validateCode={validateCode.ToUpper()}");

54return JsonConvert.DeserializeObject<YsResult>(str);

55 }

56

57///<summary>

58/// 关闭视频加密

59///</summary>

60///<param name="deviceSerial">设备序列号</param>

61///<param name="validateCode">设备验证码</param>

62///<returns>{code:200}</returns>

63publicstaticasync Task<YsResult> OffEncryption(string deviceSerial, string validateCode)

64 {

65if (string.IsNullOrEmpty(deviceSerial) || string.IsNullOrEmpty(validateCode))

66returnnew YsResult() { code = "-1", msg = "缺少验证码或序列号" };

67string str = await HttpHelper.HttpPostAsync($"{requestUrl}api/lapp/device/encrypt/off?accessToken={GetToken().Result}&deviceSerial={deviceSerial.ToUpper()}&validateCode={validateCode.ToUpper()}");

68return JsonConvert.DeserializeObject<YsResult>(str);

69 }

70

71///<summary>

72/// 删除设备

73///</summary>

74///<param name="token"></param>

75///<param name="deviceSerial">设备序列号</param>

76///<returns>{code:200}</returns>

77publicstaticasync Task<YsResult> DeleteDevice(string deviceSerial)

78 {

79if (string.IsNullOrEmpty(deviceSerial))

80returnnew YsResult() { code = "-1", msg = "缺少序列号" };

81

82string str = await HttpHelper.HttpPostAsync($"{requestUrl}api/lapp/device/delete?accessToken={GetToken().Result}&deviceSerial={deviceSerial.ToUpper()}");

83return JsonConvert.DeserializeObject<YsResult>(str);

84 }

85

86///<summary>

87/// 获取直播地址 WSS地址 #get请求 每次获取

88///</summary>

89///<param name="token"></param>

90///<param name="deviceSerial">设备序列号</param>

91///<param name="validateCode">设备验证码</param>

92///<returns></returns>

93publicstaticasync Task<string> GetPlayWss(string deviceSerial, string validateCode)

94 {

95if (string.IsNullOrEmpty(deviceSerial) || string.IsNullOrEmpty(validateCode))

96returnnull;

97//{"retcode":0,"msg":"成功","data":{"tokens":["ot.cadfwa3t0dkdn62x5qf257es7dbq1cie-1vwkltfwtz-1w1jc79-9eabx2bbz"],"params":"&auth=1&biz=4&cln=100"}}

98string str = await HttpHelper.HttpGetAsync($"{requestUrl}jssdk/ezopen/getStreamToken?accessToken={GetToken().Result}&num=1&type=live");

99 YsResult result = JsonConvert.DeserializeObject<YsResult>(str);

100if (result.retcode == 0)

101 {

102string tokensStr = result?.data?.tokens[0];

103string paramStr = result?.data["params"];

104//wss://jsdecoder.ys7.com:20006/live?dev=设备序列号&chn=1&stream=2&ssn=刚才获取的tokens[0]+刚才获取的params的字符串。作为wssUrl,此地址可以加上checkCode=验证码作为视频加密传输。

105return $"wss://jsdecoder.ys7.com:20006/live?dev={deviceSerial}&chn=1&stream=2&ssn={tokensStr}{paramStr}&checkCode={validateCode}";

106 }

107returnnull;

108 }

109

110///<summary>

111/// 获取直播地址 #返回RTMP地址

112///</summary>

113///<param name="token"></param>

114///<param name="deviceSerial">设备序列号</param>

115///<returns>返回rtmp</returns>

116publicstaticasync Task<string> GetPlayRtmp(string deviceSerial)

117 {

118if (string.IsNullOrEmpty(deviceSerial))

119returnnull;

120string str = await HttpHelper.HttpPostAsync($"{requestUrl}api/lapp/live/address/get?accessToken={GetToken().Result}&source={deviceSerial}:1");

121 YsResult result = JsonConvert.DeserializeObject<YsResult>(str);

122if (result.code.Equals("200"))

123return result?.data[0]?.rtmp;

124returnnull;

125 }

126

127///<summary>

128/// 获取设备可有的权限

129///</summary>

130///<param name="token"></param>

131///<param name="deviceSerial">设备序列号</param>

132///<returns>data:

133///{

134/// supprot_encrypt 是否支持视频图像加密 0 - 不支持, 1 - 支持

135/// support_modify_pwd 是否支持修改设备加密密码: 0 - 不支持, 1 - 支持

136/// ptz_top_bottom 是否支持云台上下转动 0 - 不支持, 1 - 支持

137/// ptz_left_right 是否支持云台左右转动 0 - 不支持, 1 - 支持

138/// ptz_45 是否支持云台45度方向转动 0 - 不支持, 1 - 支持

139/// ptz_zoom 是否支持云台缩放控制 0 - 不支持, 1 - 支持

140/// ptz_focus 是否支持焦距模式 0 - 不支持, 1 - 支持

141///}code: 200

142///</returns>

143publicstaticasync Task<YsResult<YsRoles>> GetDeviceRole(string deviceSerial)

144 {

145if (string.IsNullOrEmpty(deviceSerial))

146returnnew YsResult<YsRoles>() { code = "-1", msg = "缺少序列号" };

147

148string str = await HttpHelper.HttpPostAsync($"{requestUrl}api/lapp/device/capacity?accessToken={GetToken().Result}&deviceSerial={deviceSerial.ToUpper()}");

149return JsonConvert.DeserializeObject<YsResult<YsRoles>>(str);

150 }

151

152///<summary>

153/// 云台控制开始

154///</summary>

155///<param name="token"></param>

156///<param name="deviceSerial">设备序列号</param>

157///<param name="direction">方向 (操作命令:0 - 上,1 - 下,2 - 左,3 - 右,4 - 左上,5 - 左下,6 - 右上,7 - 右下,8 - 放大,9 - 缩小,10 - 近焦距,11 - 远焦距)</param>

158///<param name="speed">速度 (云台速度:0 - 慢,1 - 适中,2 - 快)</param>

159///<returns>{code:200}</returns>

160publicstaticasync Task<YsResult> CradleControlStarts(string token, string deviceSerial, int direction, int speed)

161 {

162if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(deviceSerial))

163returnnull;

164string str = await HttpHelper.HttpPostAsync($"{requestUrl}api/lapp/device/ptz/start?accessToken={token}&deviceSerial={deviceSerial}&channelNo=1&direction={direction}&speed={speed}");

165return JsonConvert.DeserializeObject<YsResult>(str);

166 }

167

168///<summary>

169/// 云台控制结束

170///</summary>

171///<param name="token"></param>

172///<param name="deviceSerial">设备序列号</param>

173///<param name="direction">方向 (操作命令:0-上,1-下,2-左,3-右,4-左上,5-左下,6-右上,7-右下,8-放大,9-缩小,10-近焦距,11-远焦距)</param>

174///<returns>{code:200}</returns>

175publicstaticasync Task<YsResult> CradleControlEnd(string token, string deviceSerial, int direction)

176 {

177if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(deviceSerial))

178returnnull;

179string str = await HttpHelper.HttpPostAsync($"{requestUrl}api/lapp/device/ptz/stop?accessToken={token}&deviceSerial={deviceSerial}&channelNo=1&direction={direction}");

180return JsonConvert.DeserializeObject<YsResult>(str);

181 }

182

183///<summary>

184/// 获取单个设备信息

185///</summary>

186///<param name="token"></param>

187///<param name="deviceSerial">设备序列号</param>

188///<returns></returns>

189publicstaticasync Task<YsResult> GetDeviceInfo(string deviceSerial)

190 {

191if (string.IsNullOrEmpty(deviceSerial))

192returnnull;

193string str = await HttpHelper.HttpPostAsync($"{requestUrl}api/lapp/device/info?accessToken={GetToken().Result}&deviceSerial={deviceSerial}");

194 YsResult result = JsonConvert.DeserializeObject<YsResult>(str);

195if (result.code.Equals("200"))

196return result;

197returnnull;

198 }

199

200///<summary>

201/// 开通直播功能

202///</summary>

203///<param name="deviceSerial">设备序列号</param>

204///<returns></returns>

205publicstaticasync Task<YsResult> LiveOpen(string deviceSerial)

206 {

207if (string.IsNullOrEmpty(deviceSerial))

208returnnull;

209string str = await HttpHelper.HttpPostAsync($"{requestUrl}api/lapp/live/video/open?accessToken={GetToken().Result}&source={deviceSerial}:1");

210return JsonConvert.DeserializeObject<YsResult>(str);

211 }

212

213

214 }

215

216///<summary>

217/// 萤石云返回对象

218///</summary>

219publicclass YsResult<T>

220 {

221publicstring code { get; set; }

222public T data { get; set; }

223publicstring msg { get; set; }

224publicint retcode { get; set; }

225 }

226publicclass YsResult : YsResult<dynamic>

227 {

228 }

229

230///<summary>

231/// 萤石云设备能力集

232///</summary>

233publicclass YsRoles

234 {

235///<summary>

236/// 是否支持视频图像加密 0 - 不支持, 1 - 支持

237///</summary>

238publicint supprot_encrypt { get; set; } = 0;

239///<summary>

240/// 是否支持修改设备加密密码: 0 - 不支持, 1 - 支持

241///</summary>

242publicint support_modify_pwd { get; set; } = 0;

243///<summary>

244/// 是否支持云台上下转动 0 - 不支持, 1 - 支持

245///</summary>

246publicint ptz_top_bottom { get; set; } = 0;

247///<summary>

248/// 是否支持云台左右转动 0 - 不支持, 1 - 支持

249///</summary>

250publicint ptz_left_right { get; set; } = 0;

251///<summary>

252/// 是否支持云台45度方向转动 0 - 不支持, 1 - 支持

253///</summary>

254publicint ptz_45 { get; set; } = 0;

255///<summary>

256/// 是否支持云台缩放控制 0 - 不支持, 1 - 支持

257///</summary>

258publicint ptz_zoom { get; set; } = 0;

259///<summary>

260/// 是否支持焦距模式 0 - 不支持, 1 - 支持

261///</summary>

262publicint ptz_focus { get; set; } = 0;

263 }

264

265 }

萤石云请求封装

 

三.使用开源流媒体框架

   开源流媒体框架就很多了,常见的SRS国产的。安装 推流 拉流。可用于直播/录播/视频客服等多种场景,其定位是运营级的互联网直播服务器集群。传送门:http://www.ossrs.net/srs.release/releases/ 喜欢的可以自己去了解了解。


提醒:你所购买的摄像头硬件上都会有摄像头的名称 序列号 验证码信息,摄像头厂商比如海康会有搜索局域网内摄像头的一个工具(官网去找)。一个Web界面的后台用于设置摄像头通道 配置信息等,在局域网内连接上摄像头 浏览器地址栏输入对应的地址就可以登录当前摄像头后台。

附赠几个rtsp rtmp免费测试地址(可以先让前端用这些地址先实现播放功能):

1 rtsp://184.72.239.149/vod/mp4:BigBuckBunny_175k.mov

2 rtsp://195.200.199.8/mpeg4/media.amp

3 rtmp://media3.sinovision.net:1935/live/livestream

 End...

 

以上是 流媒体服务器、海康威视大华摄像头实现视频监控、直播解决方案 的全部内容, 来源链接: utcz.com/z/515211.html

回到顶部