2016-09-21 78 views
0

我通過以原始ImageData格式發送每幀(RGBA順序中每個像素4個字節)通過WebSocket流式傳輸視頻。當我收到客戶端上的每個幀(作爲ArrayBuffer)時,我想使用putImageData儘可能高效地將此圖像直接繪製到畫布上。將ArrayBuffer轉換爲ImageData以在畫布上進行繪製:優化

這是我目前的解決方案:

// 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

不,您的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

+0

謝謝,你的例子很有意義。不幸的是我不能使用視頻元素,因爲它必須是實時的,並且HTML5在技術上不支持流式傳輸。 – rvighne

+0

@rvighne其實它是規範的一部分。你應該可以使用'videoElement.captureStream()'方法從videoElement獲得一個MediaStream,通過'mozCaptureStream'現在前綴爲FF。那麼你應該可以通過WebRTC,socket.io或WebSocket發送它。最後,您只需將客戶端的videoElement的srcObject設置爲發送的MediaStream。我沒有服務器端的知識,但是這裏是一個前端演示,將錄製的文件轉換爲視頻流:https://jsfiddle.net/usk05sfs/ – Kaiido

+0

如果您的流只來自服務器,我認爲你可以使用MediaSource API併發送文件塊。 https://developer.mozilla.org/en-US/docs/Web/API/MediaSource – Kaiido