Web API MediaRecorder:如何强制以 60fps 录制?

Web API MediaRecorder: How do I force record at 60fps?

总结

  1. 我说的API

  2. 上下文

  3. 问题:实际结果+预期结果

  4. 我已经尝试过的

  5. 帮帮我的线索

  6. 最小且可测试的示例:要遵循的先决条件和步骤 + 来源


我说的API

https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder

上下文

我有一个 video 元素,我用不同的 src 加载和播放了几次。在两个不同的视频之间,发生了一个过渡,每个视频都出现了淡入。播放视频时,我将其绘制在 canvas 中,带有过渡和淡入。

我在 canvas 中绘制的所有内容都是使用 Web API MediaRecorder 记录的。然后我下载这个录音对应的WEBM文件

问题

实际结果

生成的 WEBM 不稳定。当我在 canvas 中绘图时,绘图是流畅的。但是 canvas 绘图记录产生的 WEBM 是生涩的。

预期结果

由 canvas 绘图记录产生的 WEBM 必须与 canvas 绘图本身一样流畅。如果不可能得到准确的结果,那么:WEBM 必须大致与 canvas 绘图本身一样流畅,我们不能说它是生涩的。

我已经尝试过的

  1. 首先,我尝试给方法[=14=设置了1ms、16ms(对应60fps)、100ms、1000、10000等时间片],但没有用。

  2. 其次,我尝试每 16 毫秒调用一次 requestData(在一个简单的 JS timeoutlistener 每 16 毫秒执行一次),但它没有用。

帮帮我的线索

也许我错了,但我的电脑可能存在 material 限制(我有一台没有显卡的 HP Spectre x360,只有一个小显卡芯片),或我的 Chromium 浏览器的逻辑限制(我的 Ubuntu 16.04 LTS 上有版本 81.0.4044.138)。

如果你能确认这一点,那么这个问题就解决了。如果您能解释如何处理这个问题,那就太好了(Web API Media Recorder 或其他解决方案的替代解决方案)。

最小且可测试的示例

先决条件和要遵循的步骤

  1. 至少有 2 个 WEBM 视频(这将是输入视频,记住:我们要输出一个包含 canvas 绘图的新视频,它本身包含这两个输入视频加上过渡和颜色效果等)

  2. 有一个 HTTP 服务器和一个名为 "index.html" 的文件,您将使用 Chromium v​​.81 打开该文件 例如 。 Copy/paste里面有以下来源;单击 "Start" 按钮(您不需要单击 "Stop" 按钮);它会在 canvas 上绘制两个视频,带有过渡和颜色效果,它会记录 canvas 绘图,然后会出现 "Download the final output video",允许您下载输出视频。 你会发现它是生涩的。

  3. 在以下来源中,copy/paste 您的视频在名为 videos 的 JS 数组中的路径。

来源

<html>
<head>
    <title>Creating Final Video</title>
</head>

<body>
<button id="start">Start</button>
<button id="stop_recording">Stop recording</button>

<video id="video" width="320" height="240" controls>
    <source type="video/mp4">
</video>
<canvas id="canvas" width=3200 height=1608></canvas>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<script>
var videos = [];  // Populated by Selenium
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var video = document.querySelector("video");

startRecording();
$('#start').click(function() {
    showSomeMedia(0, 0);
});

function showSomeMedia(videos_counter) {
    resetVideo();

    if(videos_counter == videos.length) {
            $('#stop_recording').click();
            return;
    } else {
            setVideoSrc(videos_counter);
            setVideoListener();
            videos_counter++;
    }

    video.addEventListener('ended', () => {
         showSomeMedia(videos_counter);
    }, false);
}

function resetVideo() {
    var clone = video.cloneNode(true);
    video.remove();
    video = clone;
}

function setVideoSrc(videos_counter) {
    video.setAttribute("src", videos[videos_counter]);
    video.load();
    video.play();
}

function setVideoListener() {
    var alpha = 0.1;
    video.addEventListener('playing', () => {
      function step() {
        if(alpha < 1) {
            ctx.globalAlpha = alpha;
        }

        ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
        requestAnimationFrame(step)

        if(alpha < 1) {
            alpha += 0.00001;
        }
      }
      requestAnimationFrame(step);
    }, false)
}

function startRecording() {
  const chunks = [];
  const stream = canvas.captureStream();
  const rec = new MediaRecorder(stream);
  rec.ondataavailable = e => chunks.push(e.data);

  $('#stop_recording').click(function() {
        rec.stop();
  });
  rec.onstop = e => exportVid(new Blob(chunks, {type: 'video/webm'}));

   window.setTimeout(function() {
            rec.requestData();
   }, 1);
  rec.start();
}

function exportVid(blob) {
  const vid = document.createElement('video');
  vid.src = URL.createObjectURL(blob);
  vid.controls = true;
  document.body.appendChild(vid);
  const a = document.createElement('a');
  a.download = 'my_final_output_video.webm';
  a.href = vid.src;
  a.textContent = 'Download the final output video';
  document.body.appendChild(a);
}
</script>

</body>

</html>

问题已通过使用我的游戏笔记本电脑 (RoG) 解决,它具有良好的图形卡,能够以比我的 Spectre x360 开发笔记本电脑更高的频率进行记录。