【vue2】前端如何播放rtsp 视频流,拿到rtsp视频流地址如何处理,海康视频rtsp h264 如何播放

avatar
作者
猴君
阅读量:0

文章目录


最近在写vue2 项目其中有个需求是实时播放摄像头的视频,摄像头是 海康的设备,搞了很长时间终于监控视频出来了,记录一下,放置下次遇到。文章有点长,略显啰嗦请耐心看完。

测试

测试?测试什么?测试rtsp视频流能不能播放。

video mediaplay官网 即(VLC)

下载、安装完VLC后,打开VLC 点击媒体 -> 打开网络串流

在这里插入图片描述
将rtsp地址粘贴进去

在这里插入图片描述

不能播放的话,rtsp视频流地址有问题。
注意:视频可以播放也要查看视频的格式,如下

右击视频选择工具->编解码器信息

在这里插入图片描述

如果编解码是H264的,那么我的这种方法可以。如果是H265或者其他的话就要登录海康后台修改一下

在这里插入图片描述

以vue2 为例

新建 webrtcstreamer.js

在public文件夹下新建webrtcstreamer.js文件,直接复制粘贴,无需修改

var WebRtcStreamer = (function() {  /**   * Interface with WebRTC-streamer API  * @constructor  * @param {string} videoElement - id of the video element tag  * @param {string} srvurl -  url of webrtc-streamer (default is current location) */ var WebRtcStreamer = function WebRtcStreamer (videoElement, srvurl) { 	if (typeof videoElement === "string") { 		this.videoElement = document.getElementById(videoElement); 	} else { 		this.videoElement = videoElement; 	} 	this.srvurl           = srvurl || location.protocol+"//"+window.location.hostname+":"+window.location.port; 	this.pc               = null;      	this.mediaConstraints = { offerToReceiveAudio: true, offerToReceiveVideo: true };  	this.iceServers = null; 	this.earlyCandidates = []; }  WebRtcStreamer.prototype._handleHttpErrors = function (response) {     if (!response.ok) {         throw Error(response.statusText);     }     return response; }  /**   * Connect a WebRTC Stream to videoElement   * @param {string} videourl - id of WebRTC video stream  * @param {string} audiourl - id of WebRTC audio stream  * @param {string} options -  options of WebRTC call  * @param {string} stream  -  local stream to send */ WebRtcStreamer.prototype.connect = function(videourl, audiourl, options, localstream) { 	this.disconnect(); 	 	// getIceServers is not already received 	if (!this.iceServers) { 		console.log("Get IceServers"); 		 		fetch(this.srvurl + "/api/getIceServers") 			.then(this._handleHttpErrors) 			.then( (response) => (response.json()) ) 			.then( (response) =>  this.onReceiveGetIceServers(response, videourl, audiourl, options, localstream)) 			.catch( (error) => this.onError("getIceServers " + error )) 				 	} else { 		this.onReceiveGetIceServers(this.iceServers, videourl, audiourl, options, localstream); 	} }  /**   * Disconnect a WebRTC Stream and clear videoElement source */ WebRtcStreamer.prototype.disconnect = function() {		 	if (this.videoElement?.srcObject) { 		this.videoElement.srcObject.getTracks().forEach(track => { 			track.stop() 			this.videoElement.srcObject.removeTrack(track); 		}); 	} 	if (this.pc) { 		fetch(this.srvurl + "/api/hangup?peerid=" + this.pc.peerid) 			.then(this._handleHttpErrors) 			.catch( (error) => this.onError("hangup " + error ))  		 		try { 			this.pc.close(); 		} 		catch (e) { 			console.log ("Failure close peer connection:" + e); 		} 		this.pc = null; 	} }      /* * GetIceServers callback */ WebRtcStreamer.prototype.onReceiveGetIceServers = function(iceServers, videourl, audiourl, options, stream) { 	this.iceServers       = iceServers; 	this.pcConfig         = iceServers || {"iceServers": [] }; 	try {             		this.createPeerConnection();  		var callurl = this.srvurl + "/api/call?peerid=" + this.pc.peerid + "&url=" + encodeURIComponent(videourl); 		if (audiourl) { 			callurl += "&audiourl="+encodeURIComponent(audiourl); 		} 		if (options) { 			callurl += "&options="+encodeURIComponent(options); 		} 		 		if (stream) { 			this.pc.addStream(stream); 		}                  // clear early candidates 		this.earlyCandidates.length = 0; 		 		// create Offer 		this.pc.createOffer(this.mediaConstraints).then((sessionDescription) => { 			console.log("Create offer:" + JSON.stringify(sessionDescription)); 			 			this.pc.setLocalDescription(sessionDescription) 				.then(() => { 					fetch(callurl, { method: "POST", body: JSON.stringify(sessionDescription) }) 						.then(this._handleHttpErrors) 						.then( (response) => (response.json()) ) 						.catch( (error) => this.onError("call " + error )) 						.then( (response) =>  this.onReceiveCall(response) ) 						.catch( (error) => this.onError("call " + error )) 				 				}, (error) => { 					console.log ("setLocalDescription error:" + JSON.stringify(error));  				}); 			 		}, (error) => {  			alert("Create offer error:" + JSON.stringify(error)); 		});  	} catch (e) { 		this.disconnect(); 		alert("connect error: " + e); 	}	     }   WebRtcStreamer.prototype.getIceCandidate = function() { 	fetch(this.srvurl + "/api/getIceCandidate?peerid=" + this.pc.peerid) 		.then(this._handleHttpErrors) 		.then( (response) => (response.json()) ) 		.then( (response) =>  this.onReceiveCandidate(response)) 		.catch( (error) => this.onError("getIceCandidate " + error )) } 					 /* * create RTCPeerConnection  */ WebRtcStreamer.prototype.createPeerConnection = function() { 	console.log("createPeerConnection  config: " + JSON.stringify(this.pcConfig)); 	this.pc = new RTCPeerConnection(this.pcConfig); 	var pc = this.pc; 	pc.peerid = Math.random();		 	 	pc.onicecandidate = (evt) => this.onIceCandidate(evt); 	pc.onaddstream    = (evt) => this.onAddStream(evt); 	pc.oniceconnectionstatechange = (evt) => {   		console.log("oniceconnectionstatechange  state: " + pc.iceConnectionState); 		if (this.videoElement) { 			if (pc.iceConnectionState === "connected") { 				this.videoElement.style.opacity = "1.0"; 			}			 			else if (pc.iceConnectionState === "disconnected") { 				this.videoElement.style.opacity = "0.25"; 			}			 			else if ( (pc.iceConnectionState === "failed") || (pc.iceConnectionState === "closed") )  { 				this.videoElement.style.opacity = "0.5"; 			} else if (pc.iceConnectionState === "new") { 				this.getIceCandidate(); 			} 		} 	} 	pc.ondatachannel = function(evt) {   		console.log("remote datachannel created:"+JSON.stringify(evt)); 		 		evt.channel.onopen = function () { 			console.log("remote datachannel open"); 			this.send("remote channel openned"); 		} 		evt.channel.onmessage = function (event) { 			console.log("remote datachannel recv:"+JSON.stringify(event.data)); 		} 	} 	pc.onicegatheringstatechange = function() { 		if (pc.iceGatheringState === "complete") { 			const recvs = pc.getReceivers(); 		 			recvs.forEach((recv) => { 			  if (recv.track && recv.track.kind === "video") { 				console.log("codecs:" + JSON.stringify(recv.getParameters().codecs)) 			  } 			}); 		  } 	}  	try { 		var dataChannel = pc.createDataChannel("ClientDataChannel"); 		dataChannel.onopen = function() { 			console.log("local datachannel open"); 			this.send("local channel openned"); 		} 		dataChannel.onmessage = function(evt) { 			console.log("local datachannel recv:"+JSON.stringify(evt.data)); 		} 	} catch (e) { 		console.log("Cannor create datachannel error: " + e); 	}	 	 	console.log("Created RTCPeerConnnection with config: " + JSON.stringify(this.pcConfig) ); 	return pc; }   /* * RTCPeerConnection IceCandidate callback */ WebRtcStreamer.prototype.onIceCandidate = function (event) { 	if (event.candidate) { 		if (this.pc.currentRemoteDescription)  { 			this.addIceCandidate(this.pc.peerid, event.candidate);					 		} else { 			this.earlyCandidates.push(event.candidate); 		} 	}  	else { 		console.log("End of candidates."); 	} }   WebRtcStreamer.prototype.addIceCandidate = function(peerid, candidate) { 	fetch(this.srvurl + "/api/addIceCandidate?peerid="+peerid, { method: "POST", body: JSON.stringify(candidate) }) 		.then(this._handleHttpErrors) 		.then( (response) => (response.json()) ) 		.then( (response) =>  {console.log("addIceCandidate ok:" + response)}) 		.catch( (error) => this.onError("addIceCandidate " + error )) } 				 /* * RTCPeerConnection AddTrack callback */ WebRtcStreamer.prototype.onAddStream = function(event) { 	console.log("Remote track added:" +  JSON.stringify(event)); 	 	this.videoElement.srcObject = event.stream; 	var promise = this.videoElement.play(); 	if (promise !== undefined) { 	  promise.catch((error) => { 		console.warn("error:"+error); 		this.videoElement.setAttribute("controls", true); 	  }); 	} } 		 /* * AJAX /call callback */ WebRtcStreamer.prototype.onReceiveCall = function(dataJson) {  	console.log("offer: " + JSON.stringify(dataJson)); 	var descr = new RTCSessionDescription(dataJson); 	this.pc.setRemoteDescription(descr).then(() =>  {  			console.log ("setRemoteDescription ok"); 			while (this.earlyCandidates.length) { 				var candidate = this.earlyCandidates.shift(); 				this.addIceCandidate(this.pc.peerid, candidate);				 			} 		 			this.getIceCandidate() 		} 		, (error) => {  			console.log ("setRemoteDescription error:" + JSON.stringify(error));  		}); }	  /* * AJAX /getIceCandidate callback */ WebRtcStreamer.prototype.onReceiveCandidate = function(dataJson) { 	console.log("candidate: " + JSON.stringify(dataJson)); 	if (dataJson) { 		for (var i=0; i<dataJson.length; i++) { 			var candidate = new RTCIceCandidate(dataJson[i]); 			 			console.log("Adding ICE candidate :" + JSON.stringify(candidate) ); 			this.pc.addIceCandidate(candidate).then( () =>      { console.log ("addIceCandidate OK"); } 				, (error) => { console.log ("addIceCandidate error:" + JSON.stringify(error)); } ); 		} 		this.pc.addIceCandidate(); 	} }   /* * AJAX callback for Error */ WebRtcStreamer.prototype.onError = function(status) { 	console.log("onError:" + status); }  return WebRtcStreamer; })();  if (typeof window !== 'undefined' && typeof window.document !== 'undefined') { 	window.WebRtcStreamer = WebRtcStreamer; } if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { 	module.exports = WebRtcStreamer; } 

下载webrtc-streamer

资源在最上面
也可以去github上面下载:webrtc-streamer
下载完后解压,打开,启动

在这里插入图片描述
出现下面这个页面就是启动成功了,留意这里的端口号,就是我选出来的部分,一般都是默认8000,不排除其他情况

在这里插入图片描述

检查一下也没用启动成功,http://127.0.0.1:8000/ 粘贴到浏览器地址栏回车查看,启动成功能看到电脑当前页面(这里的8000就是启动的端口号,启动的是多少就访问多少)

video.vue

新建video.js (位置自己决定,后面要引入的)

video.js中要修改两个地方,第一个是引入webrtcstreamer.js路径,第二个地方是ip地址要要修改为自己的ip加上启动的端口号(即上面的8000),不知道电脑ip地址的看下面一行

怎么查看自己的ip地址打开cmd 黑窗口(即dos窗口),输入ipconfig回车,在里面找到 IPv4 地址 就是了

<template>   <div id="video-contianer">     <video       class="video"       ref="video"       preload="auto"       autoplay="autoplay"       muted       width="600"       height="400"     />     <div       class="mask"       @click="handleClickVideo"       :class="{ 'active-video-border': selectStatus }"     ></div>   </div> </template>  <script> import WebRtcStreamer from "../../public/webrtcstreamer";  export default {   name: "videoCom",   props: {     rtsp: {       type: String,       required: true,     },     isOn: {       type: Boolean,       default: false,     },     spareId: {       type: Number,     },     selectStatus: {       type: Boolean,       default: false,     },   },   data() {     return {       socket: null,       result: null, // 返回值       pic: null,       webRtcServer: null,       clickCount: 0, // 用来计数点击次数     };   },   watch: {     rtsp() {       // do something       console.log(this.rtsp);       this.webRtcServer.disconnect();       this.initVideo();     },   },   destroyed() {     this.webRtcServer.disconnect();   },   beforeCreate() {     window.onbeforeunload = () => {       this.webRtcServer.disconnect();     };   },   created() {},   mounted() {     this.initVideo();   },   methods: {     initVideo() {       try {         //连接后端的IP地址和端口         this.webRtcServer = new WebRtcStreamer(           this.$refs.video,           `http://192.168.0.24:8000`         );         //向后端发送rtsp地址         this.webRtcServer.connect(this.rtsp);       } catch (error) {         console.log(error);       }     },     /* 处理双击 单机 */     dbClick() {       this.clickCount++;       if (this.clickCount === 2) {         this.btnFull(); // 双击全屏         this.clickCount = 0;       }       setTimeout(() => {         if (this.clickCount === 1) {           this.clickCount = 0;         }       }, 250);     },     /* 视频全屏 */     btnFull() {       const elVideo = this.$refs.video;       if (elVideo.webkitRequestFullScreen) {         elVideo.webkitRequestFullScreen();       } else if (elVideo.mozRequestFullScreen) {         elVideo.mozRequestFullScreen();       } else if (elVideo.requestFullscreen) {         elVideo.requestFullscreen();       }     },     /*      ison用来判断是否需要更换视频流     dbclick函数用来双击放大全屏方法     */     handleClickVideo() {       if (this.isOn) {         this.$emit("selectVideo", this.spareId);         this.dbClick();       } else {         this.btnFull();       }     },   }, }; </script>  <style scoped lang="scss"> .active-video-border {   border: 2px salmon solid; } #video-contianer {   position: relative;   // width: 100%;   // height: 100%;   .video {     // width: 100%;     // height: 100%;     // object-fit: cover;   }   .mask {     position: absolute;     top: 0;     left: 0;     width: 100%;     height: 100%;     cursor: pointer;   } } </style>  

页面中调用

在页面中引入video.vue,并注册。将rtsp视频地址传过去就好了,要显示几个视频就调用几次

在这里插入图片描述

回到页面看,rtsp视频已经可以播放了

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!