如何编辑 Chrome MediaRecorder 捕获的 .webm Blob

How to edit .webm Blobs captured by Chrome MediaRecorder

在Chrome。我正在使用 MediaRecorder and canvas.captureStream() 创建 canvas.

的 webm 文件
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 文件很好,我遇到的问题是因为 computer/overhead,我不能总是足够快地绘制 canvas 以使其成为完整的 60每秒帧数。在 canvas 本身,我不介意较低的帧率,但绘制到 canvas 的延迟被转化为 webm,我留下了 x0.9 速度的视频。

我尝试通过使用 canvas.captureStream(0) 一次只捕获一个帧并将其与每个 canvas 渲染相匹配来解决这个问题。但这失败了,因为我无法指定每一帧应该持续的持续时间,并且文件大小变得巨大,因为每一帧都有所有 header 信息。

我可以在我的 blob 数组中看到前 131 个 blob 是常量,而 blob 132 的数据量非常大。在那之后,通常有大约 7 个 1 字节的间隔块,然后是一个包含更多数据的单个块。我知道前 132 个斑点是 header 信息 + 我的第一帧。我想每一帧都有大量数据的斑点。我还假设 1 字节间隔符 blob 与帧持续时间或暂停一段时间有关。

我想做的是能够修改那些间隔块以指定帧的确切持续时间。我尝试通过复制我知道帧速率理想的 2 帧之间的 7 个间隔块来手动执行此操作,然后删除所有其他间隔块并在每帧之间粘贴这些理想的间隔块,但输出文件没有播放。

我是不是误解了 blob 数据?有什么方法可以通过修改 blob 数据手动指定帧持续的持续时间,或者我是否坚持使用可以绘制到 canvas 的任何帧率?

我能够通过在超时时暂停和恢复记录器并在再次暂停前请求帧来定义与 canvas 刷新率分开的帧率:

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);

这样,实际canvas绘图或更新进度条等的任何滞后都不会影响记录器的帧收集。 recorder.requestData() 似乎没有必要,但似乎也没有任何缺点。为清楚起见,将其包含在此处。

我没有仔细检查过,但是根据recorder.start()是否收集初始帧以及您的canvas是否为空,开头可能会出现双帧。

我在尝试使用 canvas.captureStream()MediaRecorder 逐帧制作视频时遇到了很多困难,包括使用您的 pause/resume 解决方案。这似乎根本不是预期用途。然而,我找到了一个专门用于此目的的库:CCapture.js。它对我有用。它通过对 canvas 的图像转储进行采样并在之后加入它们来工作。在此过程中,它会覆盖一些内部功能,因此可能对所有事情都不安全(?)。但它使工作变得非常容易。此外,它允许多种输出格式,根据我有限的经验,webm 输出的质量比使用 MediaRecorder 实现的质量要好得多。