如何正确记录画布中的流? [英] How to properly record stream from canvas?

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

问题描述

情况:

我需要执行以下操作:


  • < video> 获取视频并在< canvas>

将画布中的流记录为Blob

Record the stream from the canvas as a Blob

就是这样。第一部分没关系。
对于第二部分,我设法记录一个Blob,问题是Blob是空的。

That's it. First part is okay. 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

这是 console.log Blob的

THE FIDDLE:

这是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.

问题:

从画布录制流的正确方法是什么?

代码中有什么问题吗?

你知道为什么Blob出来了吗?

What is the proper way to the record a stream from a canvas?
Is there something wrong in the code?
Do you know why the Blob came 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 <的最终Blob / code> 事件,它将发出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>的captureStream MediaStream。

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

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