【问题标题】:Convert ArrayBuffer into ImageData for drawing on canvas: optimization将 ArrayBuffer 转换为 ImageData 以在画布上绘图:优化
【发布时间】:2017-01-29 03:19:05
【问题描述】:

我通过 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,这可能是垃圾收集器的问题。

这些理论是否正确,如果正确,我可以使用什么技巧来尽可能快地做到这一点?我愿意接受特定于浏览器的答案。

【问题讨论】:

    标签: javascript canvas optimization arraybuffer putimagedata


    【解决方案1】:

    不,您的 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 实际上它是规范的一部分。您应该能够使用 videoElement.captureStream() 方法从 videoElement 获取 MediaStream,目前在 FF 中通过 mozCaptureStream 前缀。然后您应该能够通过 WebRTC、socket.io 或 WebSocket 发送它。最后,您只需将客户端 videoElement 的 srcObject 设置为发送的 MediaStream。我没有服务器端知识,但是这里有一个前端演示,将录制的文件转换为视频流:jsfiddle.net/usk05sfs
    • 如果您的流仅来自服务器,我认为您可以使用 MediaSource API 并发送文件块。 developer.mozilla.org/en-US/docs/Web/API/MediaSource
    猜你喜欢
    • 1970-01-01
    • 2014-06-04
    • 1970-01-01
    • 2021-11-23
    • 2020-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-21
    相关资源
    最近更新 更多