基于canvas+webrtc 实现流式渲染 1
官方文档 webrtc :https://developer.mozilla.org/zh-CN/docs/Web/API/RTCPeerConnection
流式渲染最经典的场景是来自于steam 游戏, 可以通过云服务做gpu的计算,最后将视频流到客户端上(看上去很黑科技,其实不好用...)。 作为技术思路 前端方面也可以做类似的尝试。
webrtc 是点对点的服务,主要表现webrtc的通信原理,在本创建两个通信实例,实时操作canvas,同步到video上
知识点 :
媒体流(MediaStream)
https://developer.mozilla.org/zh-CN/docs/Web/API/MediaStream
MSE(Media Source Extensions):
媒体源扩展 API(MSE) 提供了实现无插件且基于 Web 的流媒体的功能。使用 MSE,媒体串流能够通过 JavaScript 创建,并且能通过使用 <audio>
和 <video>
元素进行播放。(图片视频直播都是流)
场景:基于mse的能力,可以通过blob url 向vedio标签中灌入二进制流(fpm4格式流), 或者通过canvas组件实现直播。
canvas(fabric.js)
webrtc(adapter.js)
1. peer-to-peer 点对点的
步骤:
1. pc2 监听webrtc , vedio监听组件传入mediastream
const video = document.getElementById('video'); function gotRemoteStream(e) { if (video.srcObject !== e.streams[0]) { video.srcObject = e.streams[0]; console.log('pc2 received remote stream'); } } video.addEventListener('loadedmetadata', function() { console.log(`Remote video videoWidth: ${this.videoWidth}px, videoHeight: ${this.videoHeight}px`); });
2.pc1 canvans 捕捉画布,通过webrtc 发送blob
//webrtc 官方文档 https://developer.mozilla.org/zh-CN/docs/Web/API/RTCPeerConnection/createOffer const canvas = document.getElementById('canvas'); const stream = canvas.captureStream(); console.log('Got stream from canvas'); //创建一个新建的 RTCPeerConnection实例,它代表了本地端机器与远端机器的一条连接。 let pc1 = new RTCPeerConnection(servers); pc1.onicecandidate = e => onIceCandidate(pc1, e); pc1.oniceconnectionstatechange = e => onIceStateChange(pc1, e); stream.getTracks().forEach( track => { pc1.addTrack( track, stream ); } ); // pc1 端通过 createOffer 动创建一个SDP offer,启动一个新的WebRTC去连接远程端点 pc1.createOffer(onCreateOfferSuccess, ()=>{}, offerOptions); function onCreateOfferSuccess(desc) { //setlocaldescription( ) 设置本地的描述信息 pc1.setLocalDescription(desc, () => {}, ()=>{}); // setRemoteDescription,设置远端的描述信息。 pc2.setRemoteDescription(desc, () => {}, ()=>{}); // pc2端 通过createAnswer 创建出自己的 SDP 描述 pc2.createAnswer(onCreateAnswerSuccess, ()=>{}); } function onCreateAnswerSuccess(desc) { pc2.setLocalDescription(desc, () => {}, onSetSessionDescriptionError); pc1.setRemoteDescription(desc, () => {}, onSetSessionDescriptionError); }