首页 > 解决方案 > 如何根据大小而不是时间从(网络)MediaRecorder 获取流数据?

问题描述

我目前正在使用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 台媒体记录器在性能方面表现出色,我也会接受这一点并处理它造成的并发症。

标签: javascripttypescriptnavigatorweb-mediarecorder

解决方案


组合块

可以在事后将块与new Blob(blobArray). 如果您绝对需要处理特定大小的 blob,则可以使用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 APIbitsPerSecond中的(以及audioBitsPerSecondand videoBitsPerSecond)选项感兴趣,这可能会在给定的记录时间量内为您提供更多可预测的 blob 大小。不过,这可能会影响视频和音频质量。


推荐阅读