我正在用Angular和grpc-web流编写前端应用程序。目标是以60-100 FPS的速度渲染流中的图像有效负载。它以前是在WPF中实现的,但现在我需要切换到Web前端。我注意到,即使二进制映像已传输到浏览器,我仍然需要创建一个Blob URL进行下载。
我当前的策略是:
URL.revokeObjectURL(this.ImageSrc);
const blob = new Blob([res.getImage_asU8()], {type: res.getType()});
this.ImageSrc = URL.createObjectURL(blob);
但是,存在两个主要的性能问题
1. CPU使用率很高。我使用CDT对其进行了分析,发现new Blob()
占用了最多的脚本时间。
2.尽管对象已经在内存中,但是在创建Blob URL之后,img
元素似乎又从内存中下载了Blob。通过CDT网络监控,我发现每个内存Blob都需要10到30毫秒才能“下载”。 (更新:可能是由于CDT降低了性能)
除了为Blob创建URL外,我还尝试使用base64渲染图像。图片为800 * 600单色png,在这种情况下,base64不能正常工作。
我想知道是否可以将流传输的二进制图像直接呈现到元素(img,canvas或svg)上而不创建blob或从内存中重新下载blob。谢谢!
我制作了一个test project来比较图像更新速度。 我打算比较三种使用情况,但是我不知道如何在浏览器JavaScript中将png / jpeg二进制有效地解码为RGBA,所以我跳过了。
因此,当并行传输10张图像时,图像+ Blob解决方案似乎比基于画布的方法快。
令人惊讶的是,img可以保持这种速度。画布似乎太重了,无法以这种速度进行更新。
<img> + createObjectURL
应该适合大多数FPS较高的情况。 **不要相信CDT中的时间,因为CDT会减慢执行速度**。我在这里没有做非常仔细的比较,如果我没有正确使用canvas元素,请告诉我。此外,只要及时调用<img> + createObjectURL
,URL.revokeObjectURL
的堆使用率就会比使用画布低得多。
答案 0 :(得分:0)
这实际上取决于图像的来源。
这里最简单的想法是将其作为视频流发送。
如果这不可行,那么您可以考虑将原始位图数据发送为Uint8 [R,G,B,A,R,G,B,A],这样您就可以直接将其推送到画布上,因为您具有固定的宽度和高度。
const width = 300;
const height = 150;
const service = new Worker(getWorkerURL());
const ctx = canvas.getContext('2d');
service.onmessage = e => {
const img = new ImageData(e.data, 300, 150);
ctx.putImageData(img,0,0);
};
// fake service
// a simple Worker that will send a message with an Uint8ClampedArray of random data
function getWorkerURL() {
const content = `
function sendData() {
const arr = new Uint8ClampedArray(300*150*4);
for(let i = 0; i<arr.length; i++) {
if(i%4 === 3) arr[i] = 255;
arr[i] = Math.random() * 255;
}
postMessage(arr, [arr.buffer]);
if(self.requestAnimationFrame)
self.requestAnimationFrame(sendData);
else setTimeout(sendData, 16);
}
sendData();`;
const blob = new Blob([content], {type: 'application/javascript'});
return URL.createObjectURL(blob);
}
<canvas id="canvas"></canvas>
如果这也不可能,并且您必须发送二进制编码的图像,那么没有比通过<img>
元素更好的方法了,即使确实如此,这也意味着很多异步操作,例如网络操作。
当然,您可以尝试自己从接收到的ArrayBuffer中解析二进制文件,并对原始像素值进行解码,但是我的直言不讳,您将需要做大量的工作才能与内置实现竞争。 / p>
答案 1 :(得分:0)
也许一些的工作可以转移给网络工作者?
例如,createImageBitmap可以从Blob创建ImageBitmap,而ImageBitmap实现了Transferable接口,这意味着它可以在Web Worker和主线程之间进行传输。
那么,也许考虑让一名网络工作者生成ImageBitmap,然后将其传递到主线程并渲染到画布上?