将ArrayBuffer转换为ImageData以在画布上绘制:优化。

6
我正在通过WebSocket传输视频,通过以原始ImageData格式发送每个帧(按RGBA顺序每像素4字节)的方式。当我在客户端收到每个帧时(作为ArrayBuffer),我想尽可能高效地直接将该图像绘制到画布上,使用putImageData
这是我的当前解决方案:
// buffer is an ArrayBuffer representing a properly-formatted image
var array = new Uint8ClampedArray(buffer);
var image = new ImageData(array, width, height);
canvas.putImageData(image, 0, 0);

但是它相当慢。我认为原因有:

  • 数组(大约1MB)被复制了三次,一次进入Uint8ClampedArray,一次进入ImageData,最后每秒30帧复制到画布中。

  • 每帧使用new两次,这可能会对垃圾收集器造成问题。

这些理论是否正确,如果是,我可以采取什么技巧使其尽可能快?我愿意接受特定于浏览器的答案。

1个回答

5
不,ImageData的“image”和TypedArray的“array”共享完全相同的缓冲区“buffer”。
这些只是指针,您的原始缓冲区从未被“复制”。

var ctx = document.createElement('canvas').getContext('2d');

var buffer = ctx.getImageData(0,0,ctx.canvas.width, ctx.canvas.height).data.buffer;

var array = new Uint8ClampedArray(buffer);

var image = new ImageData(array, ctx.canvas.width, ctx.canvas.height);

console.log(array.buffer === buffer && image.data.buffer === buffer);

针对您的处理时间问题,最好的方法是直接将视频流发送到videoElement并使用drawImage


谢谢,你的例子很有道理。不幸的是,我不能使用视频元素,因为它必须是实时的,而HTML5在技术上不支持流媒体。 - rvighne
1
@rvighne 实际上这是规格的一部分。您应该能够使用 videoElement.captureStream() 方法从 videoElement 获取 MediaStream,目前在 FF 中通过 mozCaptureStream 进行前缀处理。然后,您应该能够通过 WebRTC、socket.io 或 WebSocket 发送它。最后,您只需要将客户端 videoElement 的 srcObject 设置为发送的 MediaStream 即可。我没有服务器端知识,但这里有一个前端演示,将录制的文件转换为视频流:https://jsfiddle.net/usk05sfs/ - Kaiido
1
如果你的流只来自服务器,我认为你可以使用MediaSource API并发送文件的块。https://developer.mozilla.org/en-US/docs/Web/API/MediaSource - Kaiido

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接