2016-12-12 28 views
3

在Chrome中。我使用MediaRecordercanvas.captureStream()來創建畫布的webm文件。如何編輯由Chrome MediaRecorder捕獲的.webm Blob

let recorder = new MediaRecorder(document.querySelector('canvas').captureStream(), {mimeType: 'video/webm'}); 
let chunks = []; 
let blob; 

recorder.ondataavailable = function(event) { 
    if (event.data.size > 0) { 
    chunks.push(event.data); 
    } 
}; 
recorder.onstop = function() { 
    blob = new Blob(chunks, {type: 'video/webm'}); 
    let url = URL.createObjectURL(blob); 
    let a = document.createElement('a'); 
    document.body.appendChild(a); 
    a.href = url; 
    a.download = Date.now()+'.webm'; 
    a.click(); 
    window.URL.revokeObjectURL(url); 
    a.parentNode.removeChild(a); 
} 
recorder.onstart = function() { 
    chunks = []; 
} 

這是調用recorder.start()開始記錄和recorder.stop()結束沿基本記錄和下載代碼。

輸出WebM檔案是很好,我現在遇到的問題是,由於低劣的電腦/開銷,我不能總是畫在畫布快足以令它一個完整的60個FPS。在畫布本身上,我並不介意較低的幀率,但繪製到畫布上的延遲被轉換爲webm,並且剩下一個x0.9速度的視頻。

我試着用canvas.captureStream(0)捕捉一次只單個幀和匹配了每個畫布渲染彌補這一點。但是這樣做失敗了,因爲我不能指定每個幀應該持續的持續時間,並且文件大小變得巨大,因爲每個幀都具有所有的頭信息。

我可以在斑點陣列看到的是,第一131個斑點是恆定的,和BLOB 132有一個非常大的數據量。之後,通常會有〜7個間隔斑點,每個間隔斑點1個字節,然後是一個包含大量數據的斑點。我知道前132個blob是頭信息+我的第一幀。我想像數據量較大的斑點是每一幀。我還假設1字節的間隔點blob與幀持續時間或暫停一段時間有關。

我想這樣做是爲了能夠修改這些隔離斑點指定幀的確切時間。我試圖通過在2幀之間複製7幀間隔斑點來手動完成此操作,我知道幀速率是理想的,然後刪除所有其他間隔並在每幀之間粘貼這些理想的間隔斑點,但輸出文件無法播放。

我誤解了blob數據嗎?有沒有辦法通過修改blob數據來手動指定幀的持續時間,還是我堅持使用任何可以畫到畫布的幀率?

+0

不知道如果我要告訴你,現在是100%真實的,但我覺得你真的不能有超過錄制的視頻的幀率控制。 fps參數僅適用於CaptureStream,但它不是MediaRecorder的設置。您唯一的選擇是[MediaRecorder構造函數](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/MediaRecorder)中的'videoBitsPerSecond'。你可以嘗試玩它。 – Kaiido

+0

@Kaiido不幸的是,這不會伎倆。 MediaRecorder實際上確實有一個我可以放置在MediaRecorder.start(時間片)中的時間片,如果設置爲1000/fps,將導致以我想要的fps進行幀捕獲。繪製框架後,我也可以手動執行.requestData()。問題是瓶頸是視頻源(即畫布刷新)。試想一下,如果我每秒畫一次畫布,那麼我的動畫是1 fps。我希望能夠記錄該畫布,然後生成一個.webm,其中該畫布動畫的每個幀都會持續一段我選擇的時間,與1 fps畫布無關。 – Bobby

+0

正如我所說我不確定以前的評論。我昨天沒有太多時間去做測試,而我的VLC從來沒有從瀏覽器錄製的視頻中返回FPS元數據......但是我的FF似乎具有與captureStream中設置的fps相同數量的mozDecodedFrame,當設置到<30fps。 (在1fps下爲10秒視頻10幀,在60 fps下爲10秒視頻297幀)。不知道它是否可靠。 – Kaiido

回答

1

我能夠通過暫停和超時恢復錄製,再次暫停前請求幀定義從畫布刷新率的幀率獨立:

let recorder = new MediaRecorder(canvas.captureStream(), {mimeType: 'video/webm'}); 
recorder.start(); 
recorder.pause(); 

function draw() { 
    context.drawImage(...); 
    recorder.resume(); 
    setTimeout(function() { 
    recorder.requestData(); 
    recorder.pause(); 

    //update progress bars or any laggy overhead stuff at this point 

    requestAnimationFrame(draw); 
    }, 1000/fps); 
} 
requestAnimationFrame(draw); 

這樣,在實際的帆布任何滯後繪圖或更新進度條等不會影響記錄器的幀採集。 recorder.requestData()似乎沒有必要,但也似乎沒有任何缺點。爲了清楚起見,這裏包括了它。

我還沒有詳細檢查,但是在開始時可能會有一個雙重框架,具體取決於recorder.start()是否收集初始框架並且您的畫布不是空白。

+0

好主意暫停/恢復,但是你的動畫循環......不知道你爲什麼在rAF循環中執行setTimeout,rAF會大約在60fps,但如果你做一個setTimeout來觸發下一次呼叫,那麼你可能會失去你的幀速率。 – Kaiido

+0

setTimeout是控制記錄器幀率的東西。我們畫到畫布上,然後開始錄製,然後在1000/fps超時後停止錄製(所以我們將重新編排一個持續1000幀/秒的單幀),然後我們處理任何開銷並移動以繪製下一幀。 – Bobby

+0

我不太關心畫布的幀率,只是錄音機。 rAF部分存在,因爲我習慣於在繪製到畫布時使用它,並且如果選項卡在背景中結束,那麼rAF會等待啓動,直到選項卡再次獲得焦點。我已經用添加了定時器的方式運行它,並且在暫停記錄器的超時時間和函數在rAF內部調用之後開始的位置之間的差異爲5毫秒,而我的fps爲30之間的區別。這是更新進度條和一些其他很小的東西。 – Bobby