首页 > 解决方案 > 如何仅在调用 stream.requestFrame() 时记录 HTML 画布并保​​存结果?

问题描述

我正在尝试使用canvas.captureStream录制 HTML 画布动画。

但是,我不想现场录制画布。

相反,我只想在画布完全绘制后按帧记录。

为了逐帧记录,我使用 canvas.captureStream(0) 提供了 0 的帧速率。这应该使它只有在调用 stream.requestFrame()时才捕获帧。

但是,我不知道如何从这里访问流,或将其保存为视频文件。理想情况下,我可以使用 MediaRecorder,但MediaRecorder.ondataavailable不与 requestFrame() 同步。这意味着它会记录所有内容,完全忽略 requestFrame()。

以下是说明我的问题的示例:

let stream;
let recording;
let downloadButton;
let chunks = [];
let recorder;
let interval;

function setup() {
    canvas = document.getElementById("canvas");
    recording = document.getElementById("recording");
    downloadButton = document.getElementById("downloadButton");
    ctx = canvas.getContext("2d");
    stream = canvas.captureStream(0);
    recorder = new MediaRecorder(stream);
    recorder.ondataavailable = function(event) {
        if (event.data && event.data.size > 0) {
            chunks.push(event.data);
        }
    }
    recorder.onstop = function() {
        let recordedBlob = new Blob(chunks, { type: "video/webm" });
        recording.src = URL.createObjectURL(recordedBlob);
        downloadButton.href = recording.src;
        downloadButton.download = "RecordedVideo.webm";
    }
}

function toggleAnimation() {
    if (interval) {
        stream.getTracks().forEach(track => track.stop());
        recorder.stop();
        window.clearInterval(interval);
        interval = undefined;
    } else {
        // I know this could be animated a lot faster, but this is just an example
        // Imagine something like raytracing, where it takes much longer to render a frame
        interval = window.setInterval(function() {
            ctx.fillStyle = "white";
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            ctx.fillStyle = "red";
            ctx.fillRect(canvas.width / 2 + (Math.random() * 50), canvas.height / 2 + (Math.random() * 50), 32, 32);
            ctx.fillStyle = "black";
            ctx.font = "16px Arial";
            ctx.fillText("How can I get this to capture frames", 16, 16);
          ctx.fillText("only when requestFrame() is called?", 16, 32);
            // This ideally would capture only the moving frames
            stream.getVideoTracks()[0].requestFrame();
        }, 500); // Example delay of 0.5 seconds between frames
        recorder.start();
    }
}
<body onload="setup();">
    <input type="button" value="Play and Record Animation / Stop and Save Recording" onclick="toggleAnimation();">
    <a id="downloadButton" class="button">Download Video</a>
    <div>
        <canvas id="canvas" width="320" height="240" style="border: 1px solid black;"></canvas>
        <video id="recording" width="320" height="240" controls></video>
  </div>
</body>

尽管可以通过降低时间延迟来避免此示例中的延迟,但想象一下诸如光线追踪之类的情况,帧之间的延迟会更大。这是我试图解决的问题类型。

任何帮助将不胜感激!

标签: javascripthtmlcanvasvideo-capturemediarecorder

解决方案


推荐阅读