簡體   English   中英

從 HTML Canvas 捕獲圖像的最快方法

[英]Fastest way to capture image from a HTML Canvas

這是我從 Canvas 播放視頻中捕獲圖像的代碼:

    let drawImage = function(time) {
        prevCtx.drawImage(videoPlayer, 0, 0, w, h);
        requestAnimationFrame(drawImage);
    }
    requestAnimationFrame(drawImage);

    let currIndex = 0;
    setInterval(function () {
        if(currIndex === 30) {
            currIndex = 0;
            console.log("Finishing video...");
            videoWorker.postMessage({action : "finish"});
        } else {
            console.log("Adding frame...");
            // w/o this `toDataURL` this loop runs at 30 cycle / second
            // so that means, this is the hot-spot and needs optimization:
            const base64img = preview.toDataURL(mimeType, 0.9);
            videoWorker.postMessage({ action: "addFrame", data: base64img});
            currIndex++;
        }
    }, 1000 / 30)

目標是在每 30 幀(應該是 1 秒)時觸發對添加的幀進行轉碼

這里的問題是preview.toDataURL(mimeType, 0.9); 至少增加 1 秒,沒有它,日志顯示currIndex === 30每秒觸發一次。 能夠捕獲至少大約 30 FPS 圖像的最佳方法是什么。 從 HTML Canvas 捕獲圖像的最快方法是什么,它不會成為實時視頻轉碼過程的瓶頸?

您可能應該修改您的項目,因為將整個視頻保存為靜止圖像會立即炸毀大多數設備的 memory。 相反,請查看能夠實時進行轉碼和壓縮的MediaStreamsMediaRecorder API。 您可以通過其captureStream()方法從 canvas 請求 MediaStream。


最快的可能是將ImageBitmap發送到您的 Worker 線程,從 canvas(像素緩沖區的簡單副本)生成這些非常快,並且可以傳輸到您的工作腳本,您應該可以從那里繪制它一個 OffscreenCanvas。

主要缺點:目前僅在最新的 Chrome 和 Firefox 中支持(通過 webgl),並且不能填充...

main.js

else {
  console.log("Adding frame...");
  const bitmap = await createImageBitmap(preview);
  videoWorker.postMessage({ action: "addFrame", data: bitmap }, [bitmap]);
  currIndex++;
}

worker.js

const canvas = new OffscreenCanvas(width,height);
const ctx = canvas.getContext('2d'); // Chrome only
onmessage = async (evt) => {
  // ...
  ctx.drawImage( evt.data.data, 0, 0 );
  const image = await canvas.convertToBlob();
  storeImage(image);
};

另一種選擇是傳輸ImageData數據。 不如 ImageBitmap 快,它仍然具有不停止壓縮部分的主線程的優點,並且由於它可以傳輸,因此發送給 Worker 的消息也不會計算繁重。
如果您是 go 這條路,您可能希望使用 Worker 線程中的類似pako (使用 PNG 圖像使用的壓縮算法)之類的東西來壓縮數據。

main.js

else {
  console.log("Adding frame...");
  const img_data = prevCtx.getImageData(0,0,width,height);
  videoWorker.postMessage({ action: "addFrame", data: img_data }, [img_data.data]);
  currIndex++;
}

worker.js

onmessage = (evt) => {
 // ...
 const image = pako.deflate(evt.data.data); // compress to store
 storeImage(image);
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM