這次主要會實作 ImageBitmap
以及 OffscreenCanvas
兩個新的 API
,這兩個目前支持度最好的目前只有最新版的 chrome
,所以目前在使用上請記得相容性問題。那就繼續往下吧!
還記得上章說過在主線程跟 worker
中傳遞的資料會在兩邊都被複製一份,所以在資料大時會造成額外的開銷,除了有實作 Transferable
介面的ArrayBuffer
、MessagePort
、ImageBitmap
、OffscreenCanvas
這幾種類型,傳遞上可以想像成物件類型的傳遞,是使用址來做為傳遞,所以不會在進行複製。
所以我們現在要做的事情就是將從 video
取回來的影像轉為 ImageBitmap
傳遞給 worker
,並且將濾鏡在裡面計算完畢。我們先在 play
成功之後進行下列動作,
captureStream
,這個將會回傳一個 MediaStream 物件,可以讓我們獲得即時的資料getVideoTracks
來獲得目前的影像 ( getVideoTracks
會回傳目前所有軌道的影像,因為我們目前只有一軌,所以直接拿第一個, MediaStream
也可以增加軌道或者音頻,如果要做編輯或混音的時候可能會用到 )video
給 ImageCapture 使用, ImageCapture
提供了一些方法可以將目前的影片保存下來,將下來我們會使用其中一個。 video
.play()
.then(() => {
console.log('play video start')
const stream = video.captureStream()
const track = stream.getVideoTracks()[0]
this.capture = new ImageCapture(track)
this.drawCanvas()
})
做完上面的初始化之後,接著在原本更新畫面的方法裡面做一些改變,主要就是使用 grabFrame,這個將會回傳一個 ImageBitmap
,所以我們就可以使用 postMessage
傳遞,要注意的是第二個參數我們使用了 [imageBitmap]
,有實作 Transferable
的物件類型,可以通過此方法,將資料不需透過複製就傳給 worker
,但要注意的是在傳遞過後,主線程就喪失了這個資料的使用權。
this.capture
.grabFrame()
.then(imageBitmap => {
worker.postMessage(
{
imageBitmap,
sliderValue: this.sliderValue,
type: 'process'
},
[imageBitmap]
)
})
.catch(err => {
// 目前發現不會每次都成功,似乎跟原本影片 fps 沒有達到瀏覽器更新頻率有關
// console.log('play video error', err)
})
接著在 worker
裡接收
let imageBitmapTmp
let sliderValueTmp
onmessage = function(e) {
if (e.data.type === 'process' && context) {
const { imageBitmap, sliderValue } = e.data
imageBitmapTmp = imageBitmap
sliderValueTmp = sliderValue
}
}
到這裡我們就成功將圖像送給 worker
,接下來遇到的問題就是我們平時是使用 Canvas
去獲得最後要修改的 ImageData
,但是在 worker
裡面卻無法獲得 DOM
,明天來看要如何解決吧!
拉達克的首都最熱鬧的一條街,雖然是首都但也是電力不穩,不過已經是這趟旅程裡面生活機能最好的地方了
今天提到了 ImageBitmap
,其實他的創造來源可以有很多種,圖片、SVG等都可以當作來源。在使用上 MDN 表示使用在 Cavas
、 WebGL
上會更有效率。而且在 worker
中也可以使用,所以如果以後有圖片需要載入的動作就可以透過 worker
進行。那就明天見囉!