vue播放rtsp视频流
一、WebRtcStreamer.js。三、videoItem.vue。二、webrtc.js。四、webrtc.vue。
·
一、WebRtcStreamer.js
const WebRtcStreamer = (function (description) {
/**
* 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)
*/
let WebRtcStreamer = function WebRtcStreamer(videoElement, srvurl) {
if (typeof videoElement === "string") {
this.videoElement = document.getElementById(videoElement)
} else {
this.videoElement = videoElement
}
this.srvurl = `${srvurl}/rtsp` || `${location.protocol}//${window.location.hostname}:${window.location.port}/rtsp`
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 received
if (!this.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()
this.pc = undefined
} catch (e) {
}
this.pc = null
}
}
/*
* GetIceServers callback
*/
WebRtcStreamer.prototype.onReceiveGetIceServers = async function (iceServers, videourl, audiourl, options, stream) {
this.iceServers = iceServers
this.pcConfig = iceServers || {"iceServers": []}
this.pcConfig.iceCandidatePoolSize = 20
try {
this.createPeerConnection()
let 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) {
for (const track of stream.getTracks()) {
this.pc.addTrack(track);
}
// this.pc.addStream(stream)
// this.pc.addTrack()
}
// clear early candidates
this.earlyCandidates.length = 0
// create Offer
let bind = this
await this.pc.createOffer(this.mediaConstraints).then(sessionDescription => {
bind.pc.setLocalDescription(sessionDescription).then(() => {
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))
}).catch(error => {
})
}).catch(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 () {
if (this.pc) {
this.pc.close()
this.pc = undefined
}
let PeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection
this.pc = new PeerConnection(this.pcConfig)
let pc = this.pc
pc.peerid = Math.random()
let bind = this
pc.onicecandidate = function (evt) {
bind.onIceCandidate.call(bind, evt)
}
// pc.onaddstream = function (evt) {
// bind.onAddStream.call(bind, evt)
// }
pc.ontrack = function (evt) {
bind.onAddStream.call(bind, evt)
}
pc.oniceconnectionstatechange = function (evt) {
console.log(bind.videoElement);
console.log(bind.videoElement.style);
if (bind.videoElement) {
if (pc.iceConnectionState === "connected") {
bind.videoElement.style.opacity = "1.0"
} else if (pc.iceConnectionState === "disconnected") {
// bind.createPeerConnection()
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) {
evt.channel.onopen = function () {
this.send("remote channel openned")
}
evt.channel.onmessage = function (event) {
}
}
pc.onicegatheringstatechange = function () {
if (pc.iceGatheringState === "complete") {
const recvs = pc.getReceivers()
recvs.forEach((recv) => {
if (recv.track && recv.track.kind === "video") {
}
})
}
}
try {
let dataChannel = pc.createDataChannel("ClientDataChannel")
dataChannel.onopen = function () {
this.send("local channel openned")
}
dataChannel.onmessage = function (evt) {
}
} catch (e) {
}
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 {
}
}
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) => {
})
.catch((error) => this.onError("addIceCandidate " + error))
}
/*
* RTCPeerConnection AddTrack callback
*/
WebRtcStreamer.prototype.onAddStream = function (event) {
// if (window.URL) {
// this.videoElement.src = window.URL.createObjectURL(event.stream) // 用来创建 video 可以播放的 src
// } else {
// this.videoElement.srcObject = event.stream
// }
let stream = new MediaStream();
stream.addTrack(event.track);
this.videoElement.srcObject = stream
}
/*
* AJAX /call callback
*/
WebRtcStreamer.prototype.onReceiveCall = function (dataJson) {
let bind = this
let SessionDescription = window.RTCSessionDescription
let deScr = new SessionDescription(dataJson)
this.pc.setRemoteDescription(deScr).then(r => {
while (bind.earlyCandidates.length) {
let candidate = bind.earlyCandidates.shift()
bind.addIceCandidate.call(bind, bind.pc.peerid, candidate)
}
bind.getIceCandidate.call(bind)
}).catch(error => {
console.log("setRemoteDescription error:" + JSON.stringify(error))
})
}
/*
* AJAX /getIceCandidate callback
*/
WebRtcStreamer.prototype.onReceiveCandidate = function (dataJson) {
let IceCandidate = window.RTCIceCandidate
if (dataJson) {
for (var i = 0; i < dataJson.length; i++) {
let candidate = new IceCandidate(dataJson[i])
this.pc.addIceCandidate(candidate).then(r => {
}).catch(error => {
console.log("addIceCandidate error:" + JSON.stringify(error))
})
}
this.pc.addIceCandidate().catch((e) => (console.log(e)))
}
}
/*
* 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
else
window.WebRtcStreamer = WebRtcStreamer
export default WebRtcStreamer
二、webrtc.js
import WebRtcStreamer from './webrtcstreamer.js'
export function doVideoPlay(elementId, vUrl, sUrl,options) {
let webRtcServer = new WebRtcStreamer(elementId, sUrl);
webRtcServer.connect(vUrl, undefined,options);
return webRtcServer
}
三、videoItem.vue
<template>
<div class="item">
<webrtc :url="value.url" muted playsinline autoplay :controls="controls" @onClick="onClick"/>
</div>
</template>
<script>
import webrtc from "./webrtc";
export default {
components: {webrtc},
name: "videoItem",
props: {
controls: {
type: Boolean,
default: true,
},
value: {
type: Object,
default: () => {
return {}
}
}
},
methods: {
onClick(url) {
this.$emit('onClick', url);
}
}
}
</script>
<style scoped lang="scss">
.item {
display: flex;
justify-content: center;
align-items: center;
/*height: 400px;*/
}
</style>
四、webrtc.vue
<template>
<video class="video" :ref="`video${ref}`"
:muted="muted"
@click="onClick"
style="object-fit: fill"
width="100%" height="100%"
:playsinline="playsinline" :autoplay="autoplay" :loop="loop"
:controls="controls"/>
</template>
<script type='text/javascript'>
import {doVideoPlay} from "./assets/js/webrtc";
export default {
props: {
muted: Boolean,
playsinline: Boolean,
autoplay: Boolean,
controls: Boolean,
loop: Boolean,
url: String,
options: String,
},
name: "video-webrtc",
mounted() {
this.doVideoPlay()
},
data() {
return {
ref: parseInt(Math.random() * 1000),
webRtcServer: undefined
}
},
methods: {
async doVideoPlay() {
this.webRtcServer = await doVideoPlay(this.$refs[`video${this.ref}`], this.url, '', this.options)
},
onClick(){
this.$emit('onClick',this.url);
}
},
beforeDestroy() {
this.webRtcServer.disconnect();
}
}
</script>
<style scoped lang="scss">
video{
width: 100%;
height: 100%;
}
</style>
五,项目使用
<template>
<div class="p_20">
<div style="display: flex;flex-wrap: wrap;justify-content: space-between">
<cus-card :title="v.name" v-for="(v,i) in list" :key="i" style="width: calc(25% - 10px);margin-bottom: 20px;min-width: unset">
<videoItem :value="v" ></videoItem>
</cus-card>
</div>
</div>
</template>
<script>
import {getVideoList} from '@/api/business/business'
import videoItem from "./components/videoItem";
export default {
components: {videoItem},
name: "videoManage",
data(){
return {
list: [],
}
},
mounted() {
this.getVideoListApi();
},
methods: {
getVideoListApi() {
return new Promise(resolve => {
getVideoList({}).then(res => {
if (res.code === 1) {
this.list = res.result.list;
resolve();
}
})
})
}
}
}
</script>
<style scoped lang="scss">
</style>
六、结构
更多推荐
已为社区贡献6条内容
所有评论(0)