当前位置:   article > 正文

vue2使用rtsp视频流接入海康威视摄像头(纯前端)_vue2 引入实时2摄像头

vue2 引入实时2摄像头

一.获取海康威视rtsp视频流

海康威视官方的RTSP最新取流格式如下:

rtsp://用户名:密码@IP:554/Streaming/Channels/101

用户名和密码

IP就是登陆摄像头时候的IP(笔者这里IP是192.168.1.210)

所以笔者的rtsp流地址就是rtsp://用户名:密码@192.168.1.210:554/Streaming/Channels/101

二. 测试rtsp流是否可以播放

1.实现RTSP协议推流需要做的配置

1.1关闭萤石云的接入

1.2调整视频编码为H.264

2.安装VLC播放器

在此下载 video mediaplay官网 即(VLC)

安装完成之后 打开VLC播放器

在VLC播放器中打开网络串流 输入rtsp地址

成功的话我们可以看到我们所显示的摄像头

如果RTSP流地址正确且取流成功,VLC的界面会显示监控画面。否则会报错,报错信息写在了日志里,在[工具]>[消息]里可以看到

三.在vue2中引用rtsp视频流形式的海康摄像头

1.新建webrtcstreamer.js文件

在public文件夹下新建webrtcstreamer.js 代码贴在下方,复制粘贴即可

  1. var WebRtcStreamer = (function() {
  2. /**
  3. * Interface with WebRTC-streamer API
  4. * @constructor
  5. * @param {string} videoElement - id of the video element tag
  6. * @param {string} srvurl - url of webrtc-streamer (default is current location)
  7. */
  8. var WebRtcStreamer = function WebRtcStreamer (videoElement, srvurl) {
  9. if (typeof videoElement === "string") {
  10. this.videoElement = document.getElementById(videoElement);
  11. } else {
  12. this.videoElement = videoElement;
  13. }
  14. this.srvurl = srvurl || location.protocol+"//"+window.location.hostname+":"+window.location.port;
  15. this.pc = null;
  16. this.mediaConstraints = { offerToReceiveAudio: true, offerToReceiveVideo: true };
  17. this.iceServers = null;
  18. this.earlyCandidates = [];
  19. }
  20. WebRtcStreamer.prototype._handleHttpErrors = function (response) {
  21. if (!response.ok) {
  22. throw Error(response.statusText);
  23. }
  24. return response;
  25. }
  26. /**
  27. * Connect a WebRTC Stream to videoElement
  28. * @param {string} videourl - id of WebRTC video stream
  29. * @param {string} audiourl - id of WebRTC audio stream
  30. * @param {string} options - options of WebRTC call
  31. * @param {string} stream - local stream to send
  32. */
  33. WebRtcStreamer.prototype.connect = function(videourl, audiourl, options, localstream) {
  34. this.disconnect();
  35. // getIceServers is not already received
  36. if (!this.iceServers) {
  37. console.log("Get IceServers");
  38. fetch(this.srvurl + "/api/getIceServers")
  39. .then(this._handleHttpErrors)
  40. .then( (response) => (response.json()) )
  41. .then( (response) => this.onReceiveGetIceServers(response, videourl, audiourl, options, localstream))
  42. .catch( (error) => this.onError("getIceServers " + error ))
  43. } else {
  44. this.onReceiveGetIceServers(this.iceServers, videourl, audiourl, options, localstream);
  45. }
  46. }
  47. /**
  48. * Disconnect a WebRTC Stream and clear videoElement source
  49. */
  50. WebRtcStreamer.prototype.disconnect = function() {
  51. if (this.videoElement?.srcObject) {
  52. this.videoElement.srcObject.getTracks().forEach(track => {
  53. track.stop()
  54. this.videoElement.srcObject.removeTrack(track);
  55. });
  56. }
  57. if (this.pc) {
  58. fetch(this.srvurl + "/api/hangup?peerid=" + this.pc.peerid)
  59. .then(this._handleHttpErrors)
  60. .catch( (error) => this.onError("hangup " + error ))
  61. try {
  62. this.pc.close();
  63. }
  64. catch (e) {
  65. console.log ("Failure close peer connection:" + e);
  66. }
  67. this.pc = null;
  68. }
  69. }
  70. /*
  71. * GetIceServers callback
  72. */
  73. WebRtcStreamer.prototype.onReceiveGetIceServers = function(iceServers, videourl, audiourl, options, stream) {
  74. this.iceServers = iceServers;
  75. this.pcConfig = iceServers || {"iceServers": [] };
  76. try {
  77. this.createPeerConnection();
  78. var callurl = this.srvurl + "/api/call?peerid=" + this.pc.peerid + "&url=" + encodeURIComponent(videourl);
  79. if (audiourl) {
  80. callurl += "&audiourl="+encodeURIComponent(audiourl);
  81. }
  82. if (options) {
  83. callurl += "&options="+encodeURIComponent(options);
  84. }
  85. if (stream) {
  86. this.pc.addStream(stream);
  87. }
  88. // clear early candidates
  89. this.earlyCandidates.length = 0;
  90. // create Offer
  91. this.pc.createOffer(this.mediaConstraints).then((sessionDescription) => {
  92. console.log("Create offer:" + JSON.stringify(sessionDescription));
  93. this.pc.setLocalDescription(sessionDescription)
  94. .then(() => {
  95. fetch(callurl, { method: "POST", body: JSON.stringify(sessionDescription) })
  96. .then(this._handleHttpErrors)
  97. .then( (response) => (response.json()) )
  98. .catch( (error) => this.onError("call " + error ))
  99. .then( (response) => this.onReceiveCall(response) )
  100. .catch( (error) => this.onError("call " + error ))
  101. }, (error) => {
  102. console.log ("setLocalDescription error:" + JSON.stringify(error));
  103. });
  104. }, (error) => {
  105. alert("Create offer error:" + JSON.stringify(error));
  106. });
  107. } catch (e) {
  108. this.disconnect();
  109. alert("connect error: " + e);
  110. }
  111. }
  112. WebRtcStreamer.prototype.getIceCandidate = function() {
  113. fetch(this.srvurl + "/api/getIceCandidate?peerid=" + this.pc.peerid)
  114. .then(this._handleHttpErrors)
  115. .then( (response) => (response.json()) )
  116. .then( (response) => this.onReceiveCandidate(response))
  117. .catch( (error) => this.onError("getIceCandidate " + error ))
  118. }
  119. /*
  120. * create RTCPeerConnection
  121. */
  122. WebRtcStreamer.prototype.createPeerConnection = function() {
  123. console.log("createPeerConnection config: " + JSON.stringify(this.pcConfig));
  124. this.pc = new RTCPeerConnection(this.pcConfig);
  125. var pc = this.pc;
  126. pc.peerid = Math.random();
  127. pc.onicecandidate = (evt) => this.onIceCandidate(evt);
  128. pc.onaddstream = (evt) => this.onAddStream(evt);
  129. pc.oniceconnectionstatechange = (evt) => {
  130. console.log("oniceconnectionstatechange state: " + pc.iceConnectionState);
  131. if (this.videoElement) {
  132. if (pc.iceConnectionState === "connected") {
  133. this.videoElement.style.opacity = "1.0";
  134. }
  135. else if (pc.iceConnectionState === "disconnected") {
  136. this.videoElement.style.opacity = "0.25";
  137. }
  138. else if ( (pc.iceConnectionState === "failed") || (pc.iceConnectionState === "closed") ) {
  139. this.videoElement.style.opacity = "0.5";
  140. } else if (pc.iceConnectionState === "new") {
  141. this.getIceCandidate();
  142. }
  143. }
  144. }
  145. pc.ondatachannel = function(evt) {
  146. console.log("remote datachannel created:"+JSON.stringify(evt));
  147. evt.channel.onopen = function () {
  148. console.log("remote datachannel open");
  149. this.send("remote channel openned");
  150. }
  151. evt.channel.onmessage = function (event) {
  152. console.log("remote datachannel recv:"+JSON.stringify(event.data));
  153. }
  154. }
  155. pc.onicegatheringstatechange = function() {
  156. if (pc.iceGatheringState === "complete") {
  157. const recvs = pc.getReceivers();
  158. recvs.forEach((recv) => {
  159. if (recv.track && recv.track.kind === "video") {
  160. console.log("codecs:" + JSON.stringify(recv.getParameters().codecs))
  161. }
  162. });
  163. }
  164. }
  165. try {
  166. var dataChannel = pc.createDataChannel("ClientDataChannel");
  167. dataChannel.onopen = function() {
  168. console.log("local datachannel open");
  169. this.send("local channel openned");
  170. }
  171. dataChannel.onmessage = function(evt) {
  172. console.log("local datachannel recv:"+JSON.stringify(evt.data));
  173. }
  174. } catch (e) {
  175. console.log("Cannor create datachannel error: " + e);
  176. }
  177. console.log("Created RTCPeerConnnection with config: " + JSON.stringify(this.pcConfig) );
  178. return pc;
  179. }
  180. /*
  181. * RTCPeerConnection IceCandidate callback
  182. */
  183. WebRtcStreamer.prototype.onIceCandidate = function (event) {
  184. if (event.candidate) {
  185. if (this.pc.currentRemoteDescription) {
  186. this.addIceCandidate(this.pc.peerid, event.candidate);
  187. } else {
  188. this.earlyCandidates.push(event.candidate);
  189. }
  190. }
  191. else {
  192. console.log("End of candidates.");
  193. }
  194. }
  195. WebRtcStreamer.prototype.addIceCandidate = function(peerid, candidate) {
  196. fetch(this.srvurl + "/api/addIceCandidate?peerid="+peerid, { method: "POST", body: JSON.stringify(candidate) })
  197. .then(this._handleHttpErrors)
  198. .then( (response) => (response.json()) )
  199. .then( (response) => {console.log("addIceCandidate ok:" + response)})
  200. .catch( (error) => this.onError("addIceCandidate " + error ))
  201. }
  202. /*
  203. * RTCPeerConnection AddTrack callback
  204. */
  205. WebRtcStreamer.prototype.onAddStream = function(event) {
  206. console.log("Remote track added:" + JSON.stringify(event));
  207. this.videoElement.srcObject = event.stream;
  208. var promise = this.videoElement.play();
  209. if (promise !== undefined) {
  210. promise.catch((error) => {
  211. console.warn("error:"+error);
  212. this.videoElement.setAttribute("controls", true);
  213. });
  214. }
  215. }
  216. /*
  217. * AJAX /call callback
  218. */
  219. WebRtcStreamer.prototype.onReceiveCall = function(dataJson) {
  220. console.log("offer: " + JSON.stringify(dataJson));
  221. var descr = new RTCSessionDescription(dataJson);
  222. this.pc.setRemoteDescription(descr).then(() => {
  223. console.log ("setRemoteDescription ok");
  224. while (this.earlyCandidates.length) {
  225. var candidate = this.earlyCandidates.shift();
  226. this.addIceCandidate(this.pc.peerid, candidate);
  227. }
  228. this.getIceCandidate()
  229. }
  230. , (error) => {
  231. console.log ("setRemoteDescription error:" + JSON.stringify(error));
  232. });
  233. }
  234. /*
  235. * AJAX /getIceCandidate callback
  236. */
  237. WebRtcStreamer.prototype.onReceiveCandidate = function(dataJson) {
  238. console.log("candidate: " + JSON.stringify(dataJson));
  239. if (dataJson) {
  240. for (var i=0; i<dataJson.length; i++) {
  241. var candidate = new RTCIceCandidate(dataJson[i]);
  242. console.log("Adding ICE candidate :" + JSON.stringify(candidate) );
  243. this.pc.addIceCandidate(candidate).then( () => { console.log ("addIceCandidate OK"); }
  244. , (error) => { console.log ("addIceCandidate error:" + JSON.stringify(error)); } );
  245. }
  246. this.pc.addIceCandidate();
  247. }
  248. }
  249. /*
  250. * AJAX callback for Error
  251. */
  252. WebRtcStreamer.prototype.onError = function(status) {
  253. console.log("onError:" + status);
  254. }
  255. return WebRtcStreamer;
  256. })();
  257. if (typeof window !== 'undefined' && typeof window.document !== 'undefined') {
  258. window.WebRtcStreamer = WebRtcStreamer;
  259. }
  260. if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
  261. module.exports = WebRtcStreamer;
  262. }

2.下载webrtc-streamer

资源在最上面
也可以去github上面下载:webrtc-streamer

下载完解压,打开文件夹,启动webrtc-streamer.exe

打开完会出现cmd一样的黑框框如下

如果没有启动成功可以在浏览器中输入http://127.0.0.1:8000/查看本地端口8000是否被其他应用程序占用,如果没有被占用打开窗口应该如下图所示(是可以看见自己的页面的)

3.封装组件video.vue(名字随意)

代码如下(但是有需要注意的地方,请看下方)

  1. <template>
  2. <div id="video-contianer">
  3. <video
  4. class="video"
  5. ref="video"
  6. preload="auto"
  7. autoplay="autoplay"
  8. muted
  9. width="600"
  10. height="400"
  11. />
  12. <div
  13. class="mask"
  14. @click="handleClickVideo"
  15. :class="{ 'active-video-border': selectStatus }"
  16. ></div>
  17. </div>
  18. </template>
  19. <script>
  20. import WebRtcStreamer from '../../public/hk/webrtcstreamer'
  21. export default {
  22. name: 'videoCom',
  23. props: {
  24. rtsp: {
  25. type: String,
  26. required: true,
  27. },
  28. isOn: {
  29. type: Boolean,
  30. default: false,
  31. },
  32. spareId: {
  33. type: Number,
  34. },
  35. selectStatus: {
  36. type: Boolean,
  37. default: false,
  38. },
  39. },
  40. data() {
  41. return {
  42. socket: null,
  43. result: null, // 返回值
  44. pic: null,
  45. webRtcServer: null,
  46. clickCount: 0, // 用来计数点击次数
  47. }
  48. },
  49. watch: {
  50. rtsp() {
  51. // do something
  52. console.log(this.rtsp)
  53. this.webRtcServer.disconnect()
  54. this.initVideo()
  55. },
  56. },
  57. destroyed() {
  58. this.webRtcServer.disconnect()
  59. },
  60. beforeCreate() {
  61. window.onbeforeunload = () => {
  62. this.webRtcServer.disconnect()
  63. }
  64. },
  65. created() {},
  66. mounted() {
  67. this.initVideo()
  68. },
  69. methods: {
  70. initVideo() {
  71. try {
  72. //连接后端的IP地址和端口
  73. this.webRtcServer = new WebRtcStreamer(
  74. this.$refs.video,
  75. `http://192.168.1.102:8000`
  76. )
  77. //向后端发送rtsp地址
  78. this.webRtcServer.connect(this.rtsp)
  79. } catch (error) {
  80. console.log(error)
  81. }
  82. },
  83. /* 处理双击 单机 */
  84. dbClick() {
  85. this.clickCount++
  86. if (this.clickCount === 2) {
  87. this.btnFull() // 双击全屏
  88. this.clickCount = 0
  89. }
  90. setTimeout(() => {
  91. if (this.clickCount === 1) {
  92. this.clickCount = 0
  93. }
  94. }, 250)
  95. },
  96. /* 视频全屏 */
  97. btnFull() {
  98. const elVideo = this.$refs.video
  99. if (elVideo.webkitRequestFullScreen) {
  100. elVideo.webkitRequestFullScreen()
  101. } else if (elVideo.mozRequestFullScreen) {
  102. elVideo.mozRequestFullScreen()
  103. } else if (elVideo.requestFullscreen) {
  104. elVideo.requestFullscreen()
  105. }
  106. },
  107. /*
  108. ison用来判断是否需要更换视频流
  109. dbclick函数用来双击放大全屏方法
  110. */
  111. handleClickVideo() {
  112. if (this.isOn) {
  113. this.$emit('selectVideo', this.spareId)
  114. this.dbClick()
  115. } else {
  116. this.btnFull()
  117. }
  118. },
  119. },
  120. }
  121. </script>
  122. <style scoped lang="scss">
  123. .active-video-border {
  124. border: 2px salmon solid;
  125. }
  126. #video-contianer {
  127. position: relative;
  128. // width: 100%;
  129. // height: 100%;
  130. .video {
  131. // width: 100%;
  132. // height: 100%;
  133. // object-fit: cover;
  134. }
  135. .mask {
  136. position: absolute;
  137. top: 0;
  138. left: 0;
  139. width: 100%;
  140. height: 100%;
  141. cursor: pointer;
  142. }
  143. }
  144. </style>

这里要注意两个地方

第一个是

第二个是

不会查看本机端口的看这里(首先使用 Win + R打开运行 输入cmd)

4.使用video封装组件播放rtsp视频流

首先我们在要使用video封装组件的地方引入并且注册video组件

之后在页面中使用video组件 并且定义了两个变量将rtsp流传给封装的video组件

效果图如下

5.使用此种方法播放的时候会默认带声音播放,如何取消(看这里)

之后声明一个方法

然后在created里面调用就静音了

到此为止海康摄像头引入vue的方法就完美完结了

如果同学们有什么好的意见或者有什么问题可以私信我

最后祝大家事业蒸蒸日上,心想事成!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/659698
推荐阅读
相关标签
  

闽ICP备14008679号