> 技术文档 > webrtc-streamer视频流播放(rstp协议h264笔记)

webrtc-streamer视频流播放(rstp协议h264笔记)

最近视频流搞得头大,关于视频流直接用web端播放比较麻烦。

1、下载前端vue代码

一个前端的播放demo,vue代码已经放到资源里面

https://download.csdn.net/download/sunnyrainflower/91249866

 前端设置rtsp地址的位置为

2、启动前需要先启动 webrtc-streamer服务作为推流服务器

webrtc-streamer的github地址为https://github.com/mpromonet/webrtc-streamer

webrtc-streamer的exe下载地址为https://github.com/mpromonet/webrtc-streamer/releases/tag/v0.8.12

启动 webrtc-streamer服务,双击exe即可 

 

启动后的效果为

  

3、前端demo 播放效果 

4、关键代码部分

// // 接受从vue组件中传过来的参数var url = location.search; //这一条语句获取了包括问号开始到参数的最后,不包括前面的路径var params = url.substr(1); //去掉问号var pa = params.split(\"&\");var s = new Object();for (var i = 0; i < pa.length; i++) {s[pa[i].split(\"=\")[0]] = unescape(pa[i].split(\"=\")[1]);}console.log(s.data)window.onload = function() {webRtcServer = new WebRtcStreamer(\"video\", \"http://127.0.0.1:8000\");webRtcServer.connect(s.data);}window.onbeforeunload = function() {webRtcServer.disconnect();}

 

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.pcOptions = { \"optional\": [{\"DtlsSrtpKeyAgreement\": true} ] };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 receivedif (!this.iceServers) {console.log(\"Get IceServers\");fetch(this.srvurl + \"/api/getIceServers\").then(this._handleHttpErrors).then( (response) => (response.json()) ).then( (response) => this.onReceiveGetIceServers.call(this,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) {this.videoElement.src = \"\";}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 candidatesthis.earlyCandidates.length = 0;// create Offervar bind = this;this.pc.createOffer(this.mediaConstraints).then(function(sessionDescription) {console.log(\"Create offer:\" + JSON.stringify(sessionDescription));bind.pc.setLocalDescription(sessionDescription, function() {fetch(callurl, { method: \"POST\", body: JSON.stringify(sessionDescription) }).then(bind._handleHttpErrors).then( (response) => (response.json()) ).catch( (error) => bind.onError(\"call \" + error )).then( (response) => bind.onReceiveCall.call(bind,response) ).catch( (error) => bind.onError(\"call \" + error ))}, function(error) {console.log (\"setLocalDescription error:\" + JSON.stringify(error)); } );}, function(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.call(this, response)).catch( (error) => bind.onError(\"getIceCandidate \" + error ))}/** create RTCPeerConnection */WebRtcStreamer.prototype.createPeerConnection = function() {console.log(\"createPeerConnection config: \" + JSON.stringify(this.pcConfig) + \" option:\"+ JSON.stringify(this.pcOptions));this.pc = new RTCPeerConnection(this.pcConfig, this.pcOptions);var pc = this.pc;pc.peerid = Math.random();var bind = this;pc.onicecandidate = function(evt) { bind.onIceCandidate.call(bind, evt); };pc.onaddstream = function(evt) { bind.onAddStream.call(bind,evt); };pc.oniceconnectionstatechange = function(evt) { console.log(\"oniceconnectionstatechange state: \" + pc.iceConnectionState);if (bind.videoElement) {if (pc.iceConnectionState === \"connected\") {bind.videoElement.style.opacity = \"1.0\";}else if (pc.iceConnectionState === \"disconnected\") {bind.videoElement.style.opacity = \"0.25\";}else if ( (pc.iceConnectionState === \"failed\") || (pc.iceConnectionState === \"closed\") ) {bind.videoElement.style.opacity = \"0.5\";} else if (pc.iceConnectionState === \"new\") {bind.getIceCandidate.call(bind)}}}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) + \"option:\"+ JSON.stringify(this.pcOptions) );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) { var bind = this; promise.catch(function(error) {console.warn(\"error:\"+error);bind.videoElement.setAttribute(\"controls\", true); });}}/** AJAX /call callback*/WebRtcStreamer.prototype.onReceiveCall = function(dataJson) {var bind = this;console.log(\"offer: \" + JSON.stringify(dataJson));var descr = new RTCSessionDescription(dataJson);this.pc.setRemoteDescription(descr, function() { console.log (\"setRemoteDescription ok\");while (bind.earlyCandidates.length) {var candidate = bind.earlyCandidates.shift();bind.addIceCandidate.call(bind, bind.pc.peerid, candidate);}bind.getIceCandidate.call(bind)}, function(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, function() { console.log (\"addIceCandidate OK\"); }, function(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 module !== \'undefined\' && typeof module.exports !== \'undefined\')module.exports = WebRtcStreamer;elsewindow.WebRtcStreamer = WebRtcStreamer;

5、总结

 webrtc-streamer只能播放h264格式的视频流,不支持h265格式,本人运行的时候出现webrtc-streamer服务崩溃,而且是经常出现,没找到原因,欢迎经验丰富的大佬指导。

此文章仅做个人笔记记录