我正在尝试使用html5 canvas
和websockets
实时传输nodejs
的内容。
html5画布的内容只是一个视频。
到目前为止,我所做的是:
我将画布转换为blob
,然后获取blob URL
并使用websockets将URL发送到我的nodejs服务器。
我得到这样的Blob URL:
canvas.toBlob(function(blob) {
url = window.URL.createObjectURL(blob);
});
每个视频帧都会生成blob URL(准确地说是每秒20帧),它们看起来像这样:
blob:null/e3e8888e-98da-41aa-a3c0-8fe3f44frt53
然后我通过websocket从服务器获取该blob URL,以便可以将其拖放到另一个画布上,以供其他用户查看。
我确实搜索了如何从Blob URL绘制到画布上,但是找不到与我想做的事情相似的事情。
所以我的问题是:
这是我想要实现的正确方法吗?任何 优点和缺点将不胜感激。
还有其他更有效的方法吗?还是我说的很对 路径?
先谢谢了。
编辑:
我应该提到我不能在该项目中使用WebRTC,而我必须用自己的所有东西来做。
为了让我现在所在的每个地方都更容易,这就是我尝试使用websocket在画布中显示上面提到的Blob URL的方式:
websocket.onopen = function(event) {
websocket.onmessage = function(evt) {
var val = evt.data;
console.log("new data "+val);
var canvas2 = document.querySelector('.canvMotion2');
var ctx2 = canvas2.getContext('2d');
var img = new Image();
img.onload = function(){
ctx2.drawImage(img, 0, 0)
}
img.src = val;
};
// Listen for socket closes
websocket.onclose = function(event) {
};
websocket.onerror = function(evt) {
};
};
问题是,当我在FireFox中运行该代码时,画布始终为空/空白,但是我在控制台中看到了Blob URL,这使我觉得自己在做错了。
在Google chrome中,我收到Not allowed to load local resource: blob:
错误。
第二编辑:
这是我现在的位置。
第一个选项
我尝试通过websocket发送整个blob,并成功地进行了管理。但是,由于某种奇怪的原因,我无法在客户端读回它!
当我查看Node.js服务器的控制台时,对于发送到服务器的每个Blob,我都能看到类似的内容:
<buffer fd67676 hdsjuhsd8 sjhjs....
第二个选项:
因此上述选项失败了,我想到了其他方法,即将每个画布框架转换为base64(jpeg),然后通过websocket将其发送到服务器,然后将这些base64图像显示/绘制到客户端的画布上。 / p>
我正在每秒发送24帧到服务器。
这有效。但是客户端画布在其中再次显示这些base64图像的速度非常慢,并且就像每秒绘制1帧一样。这就是我目前遇到的问题。
第三种选择:
我也尝试使用没有画布的视频。因此,使用WebRTC,我将video Stream
作为单个Blob 。但是我不确定如何使用它并将其发送给客户端,以便人们可以看到。
重要提示:我正在使用的该系统不是对等连接。这只是我想要实现的一种流式传输。
答案 0 :(得分:1)
OP明确表示他们无法使用它,很多情况可能是这样,
但是,如果您负担得起,那么从canvas元素获取MediaStream所需要的就是
const canvas_stream = canvas.captureStream(minimumFrameRate);
,然后只需将其添加到RTCPeerConnection:
pc.addTrack(stream.getVideoTracks()[0], stream);
下面的示例仅将MediaStream显示为<video>
元素。
let x = 0;
const ctx = canvas.getContext('2d');
draw();
startStream();
function startStream() {
// grab our MediaStream
const stream = canvas.captureStream(30);
// feed the <video>
vid.srcObject = stream;
vid.play();
}
function draw() {
x = (x + 1) % (canvas.width + 50);
ctx.fillStyle = 'white';
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.arc(x - 25, 75, 25, 0, Math.PI*2);
ctx.fill();
requestAnimationFrame(draw);
}
video,canvas{border:1px solid}
<canvas id="canvas">75</canvas>
<video id="vid" controls></video>
OP再次表示,由于其设置不匹配,他们不希望使用此解决方案,但可能对许多读者有帮助:
与其发送画布结果,不如将绘画命令发送给您的同伴,它们将在他们的同侧执行这些命令。
但是这种方法有其自身的警告:
因此,第三种绝对不那么有效的方法,就像OP尝试做的那样:
在这里我不会详细介绍,但是请记住,您要发送的是独立的图像文件,因此比起编码为视频的数据要多得多。
相反,我将集中讨论 OP的代码为什么不起作用?
首先,最好提醒一下什么是Blob(canvas.toBlob(callback)
的回调函数中提供的东西)。
Blob是一个特殊的JavaScript对象,代表二进制数据,通常存储在浏览器的内存中,或者至少存储在用户磁盘上,浏览器可以访问。
但是,此二进制数据不能直接用于JavaScript。为了能够访问它,我们需要(通过FileReader或Response对象)读取此Blob,或者创建一个BlobURI ,这是一个伪造的URI,允许大多数API指向二进制数据就像存储在真实服务器上一样,即使二进制数据仍只是在浏览器分配的内存中。
但是此BlobURI只是到浏览器内存的虚假,临时和受域限制的路径,无法与任何其他跨域文档,应用程序甚至更少的计算机共享。
所有这些说明应该发送到WebSocket的直接是Blob,而不是BlobURI。
您只能在消费者方面创建BlobURI,以便他们可以从Blob的二进制数据中加载这些图像,这些二进制数据现在位于其分配的内存中。
发射器侧:
canvas.toBlob(blob=>ws.send(blob));
消费者方面:
ws.onmessage = function(evt) {
const blob = evt.data;
const url = URL.createObjectURL(blob);
img.src = url;
};
但是实际上,为了更好地回答OP的问题,有一个最终的解决方案,在这种情况下可能是最好的,