如何根据大小而不是时间从(网络)MediaRecorder 获取流数据?

How to get stream data from (web) MediaRecorder based on size instead of time?

我目前正在使用 MediaRecorder 从用户的网络摄像头/麦克风获取视频流的块,如下所示:

navigator.mediaDevices
    .getUserMedia({audio: true, video: true})
    .then((stream) => {
      var mediaRecorder = new MediaRecorder(stream);
      mediaRecorder.start(5000);

      mediaRecorder.ondataavailable = (blobEvent) => {
        console.log('got 5 seconds of stream', blobEvent);
      }
    })

这会每 5 秒的视频发出一个流块,但是,我想要特定大小的块,而不是长度。似乎没有明确的方法可以做到这一点,因为如果不开始一个新块我就无法检查当前块的大小,而且事后我也无法将它们组合起来。这是我想出的解决方法,使用 2 个媒体记录器:

  const MIN_BLOB_SIZE = 5000000;
  var partSize = 0;
  navigator.mediaDevices
    .getUserMedia({audio: true, video: true})
    .then((stream) => {
      var mediaRecorder = new MediaRecorder(stream);
      var mediaRecorder2 = new MediaRecorder(stream)
      mediaRecorder.start();
      mediaRecorder2.start(5000)

      mediaRecorder2.ondataavailable = (blobEvent) => {
          console.log('got 5 seconds of data', blobEvent)
          const blob = blobEvent.data
          partSize += blob.size;
          if (partSize >= MIN_BLOB_SIZE) {
              partSize = 0;
              mediaRecorder.requestData();
          }
      }

      mediaRecorder.ondataavailable = (blobEvent) => {
        console.log('got a chunk at least 5mb', blobEvent);
      };
    });

但这感觉很老套,给出了不精确的块,需要我确保这两个记录器完全同步,使错误处理/边缘情况复杂化,而且我担心使用 2 个媒体记录器对性能的影响。会接受用一台媒体记录器完成这项工作的答案,或者,如果那是不可能的,如果有人可以说服我 2 台媒体记录器在性能方面表现出色,我也会接受并处理它造成的并发症。

组合块

可以事后将区块与new Blob(blobArray). If you absolutely need to process blobs of a certain size, you can use Blob.slice合并。它可能看起来像这样:

const MIN_BLOB_SIZE = 5000000;
var partSize = 0, parts = [];
navigator.mediaDevices
  .getUserMedia({audio: true, video: true})
  .then((stream) => {
    var mediaRecorder = new MediaRecorder(stream);
    mediaRecorder.start(5000);
    mediaRecorder.ondataavailable = (blobEvent) => {
        console.log('got 5 seconds of data', blobEvent);
        const blob = blobEvent.data;
        partSize += blob.size;
        parts.push(blob);
        if (partSize >= MIN_BLOB_SIZE) {
            let bigBlob = new Blob(parts, { type: blob.type });
            // if the blob size doesn't need to be precise:
            partSize = 0;
            parts = [];
            // do something with bigBlob

            // or if the blob size needs to be precise:
            // let sizedBlob = bigBlob.slice(0, MIN_BLOB_SIZE, blob.type);
            // parts = [ bigBlob.slice(MIN_BLOB_SIZE, bigBlob.size, blob.type) ];
            // partSize = parts[0].size;
            // do something with sizedBlob

        }
    };
    mediaRecorder.onstop = (blobEvent) => {
        console.log('Recording Stopped');
        const blob = blobEvent.data;
        partSize += blob.size;
        parts.push(blob);
        let bigBlob = new Blob(parts, { type: blob.type });
        // do something with bigBlob, which may be smaller than MIN_BLOB_SIZE
    };
});

使用比特率调整 Blob 大小

您可能还对 MediaRecorder API 中的 bitsPerSecond(以及 audioBitsPerSecondvideoBitsPerSecond)选项感兴趣,这可能会为您提供更可预测的 blob 大小对于给定的记录时间。不过,这可能会影响视频和音频质量。