如何正确录制 MediaStream? [英] How can I properly record a MediaStream?

查看:30
本文介绍了如何正确录制 MediaStream?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要执行以下操作:

  • 获取视频并在

将画布中的流记录为 Blob

Record the stream from the canvas as a Blob

就是这样.第一部分还可以.

That's it. The first part is okay.

对于第二部分,我设法录制了一个 Blob.问题是 Blob 是空的.

For the second part, I managed to record a Blob. The problem is that the Blob is empty.

<video id="video" controls="true" src="http://upload.wikimedia.org/wikipedia/commons/7/79/Big_Buck_Bunny_small.ogv"></video>
<canvas id="myCanvas" width="532" height="300"></canvas>

代码

// Init
console.log(MediaRecorder.isTypeSupported('video/webm')) // true
const canvas = document.querySelector("canvas")
const ctx = canvas.getContext("2d")
const video = document.querySelector("video")

// Start the video in the player
video.play()

// On play event - draw the video in the canvas
video.addEventListener('play', () => {
  function step() {
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
    requestAnimationFrame(step)
  }
  requestAnimationFrame(step);

  // Init stream and recorder
  const stream = canvas.captureStream()
  const recorder = new MediaRecorder(stream, {
    mimeType: 'video/webm',
  });

  // Get the blob data when is available
  let allChunks = [];
  recorder.ondataavailable = function(e) {
    console.log({e}) // img1
    allChunks.push(e.data);
  }

  // Start to record
  recorder.start()

  // Stop the recorder after 5s and check the result
  setTimeout(() => {
    recorder.stop()
    const fullBlob = new Blob(allChunks, { 'type' : 'video/webm' });
    const downloadUrl = window.URL.createObjectURL(fullBlob)
    console.log({fullBlob}) // img2
  }, 5000);
})

结果

这是ondataavailable事件的console.log:

这是 Blob 的 console.log:

This is the console.log of the Blob:

这里是 JSFiddle.可以在控制台查看结果:

Here is the JSFiddle. You can check the results in the console:

https://jsfiddle.net/1b7v2pen/

此行为(Blob 数据大小:0)发生在 Chrome 和 Opera 上.
在 Firefox 上,它的行为略有不同.它记录了一个非常小的视频 Blob(725 字节).视频长度应该是 5 秒,但它只是黑屏.

This behavior (Blob data size: 0) it happens on Chrome and Opera.
On Firefox it behaves slightly different. It records a very small video Blob (725 bytes). The video length is 5 seconds as it should be, but it's just a black screen.

从画布记录流的正确方法是什么?
代码有问题吗?

What is the proper way to the record a stream from a canvas?
Is there something wrong in the code?

为什么 Blob 出来是空的?

Why did the Blob come out empty?

推荐答案

MediaRecorder.stop() 是一种异步方法.

stop 算法中,有一个对 requestData 的调用,它本身会将一个任务排入队列以触发一个事件 dataavailable 与当前自上次此类事件以来的可用数据.

In the stop algorithm, there is a call to requestData, which itself will queue a task to fire an event dataavailable with the currently available data since the last such event.

这意味着同步调用 MediaRecorder#stop() 之后,最后抓取的数据还不会成为您的 allChunks 数组的一部分.不久之后它们就会变成(通常在同一个事件循环中).

This means that synchronously after you called MediaRecorder#stop() the last data grabbed will not be part of your allChunks Array yet. They will become not so long after (normally in the same event loop).

因此,当您要保存由 MediaRecorder 制作的录音时,请务必始终从 MediaRecorder 的 onstop 事件,这将发出 MediaRecorder 实际结束的信号,确实触发了它的最后一个dataavailable事件,一切都很好.

So, when you are about to save recordings made from a MediaRecorder, be sure to always build the final Blob from the MediaRecorder's onstop event, which will signal that the MediaRecorder is actually ended, did fire its last dataavailable event, and that everything is all good.

我一开始错过的一件事是,您正在请求跨域视频.如果没有正确的跨域请求,这样做会使您的画布(和 MediaElement)受到污染,因此您的 MediaStream 将被静音.

And one thing I missed at first, is that you are requesting a cross-domain video. Doing so, without the correct cross-origin request, will make your canvas (and MediaElement) tainted, so your MediaStream will be muted.

由于您尝试请求的视频来自维基媒体,您可以简单地将其作为跨源资源进行请求,但对于其他资源,您必须确保服务器配置为允许这些请求.

Since the video you are trying to request is from wikimedia, you can simply request it as a cross-origin resource, but for other resources, you'll have to be sure the server is configured to allow these requests.

const canvas = document.querySelector("canvas")
const ctx = canvas.getContext("2d")
const video = document.querySelector("video")

// Start the video in the player
video.play()

// On play event - draw the video in the canvas
video.addEventListener('play', () => {
  function step() {
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
    requestAnimationFrame(step)
  }
  requestAnimationFrame(step);
  
  // Init stream and recorder
  const stream = canvas.captureStream()
  const recorder = new MediaRecorder(stream, {
    mimeType: 'video/webm',
  });

  // Get the blob data when is available
  let allChunks = [];
  recorder.ondataavailable = function(e) {
    allChunks.push(e.data);
  }
  recorder.onstop = (e) => {
    const fullBlob = new Blob(allChunks, { 'type' : 'video/webm' });
    const downloadUrl = window.URL.createObjectURL(fullBlob)
    console.log({fullBlob})
    console.log({downloadUrl})
  }

  // Start to record
  recorder.start()

  // Stop the recorder after 5s and check the result
  setTimeout(() => {
    recorder.stop()
  }, 5000);
})

<!--add the 'crossorigin' attribute to your video -->
<video id="video" controls="true" src="https://upload.wikimedia.org/wikipedia/commons/7/79/Big_Buck_Bunny_small.ogv" crossorigin="anonymous"></video>
<canvas id="myCanvas" width="532" height="300"></canvas>

另外,我不能不注意,如果你不从画布上做任何特殊的绘图,你可能想直接保存视频源,或者至少,录制 <video>'s captureStream MediaStream 直接.

这篇关于如何正确录制 MediaStream?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆