将 canvas 数据保存为 mp4 - Javascript

Save canvas data as mp4 - Javascript

我有一个动画 canvas,我想将它转换成 mp4。我正在使用 MediaRecorder 捕获屏幕,然后转换该 Blob。我了解到 MediaRecorder 不允许在 mp4 中录制,所以我被迫在 webm 中获取 canvas。这是我尝试过的:

<canvas id="canvas"></canvas>

var recordedChunks = [];

var time = 0;
var canvas = document.getElementById("canvas");

return new Promise(function (res, rej) {
    var stream = canvas.captureStream(60);

    mediaRecorder = new MediaRecorder(stream, {
        mimeType: "video/webm; codecs=vp9"
    });

    mediaRecorder.start(time);

    mediaRecorder.ondataavailable = function (e) {
        recordedChunks.push(event.data);
        if (mediaRecorder.state === 'recording') {
            mediaRecorder.stop();
        }
    }

    mediaRecorder.onstop = function (event) {
        var blob = new Blob(recordedChunks, {
            "type": "video/webm"
        });
        var url = URL.createObjectURL(blob);
        res(url);

        var xhr = new XMLHttpRequest;
        xhr.responseType = 'blob';

        xhr.onload = function() {
            var recoveredBlob = xhr.response;
            var reader = new FileReader;

            reader.onload = function() {
                var blobAsDataUrl = reader.result;
                document.getElementById("my-video").setAttribute("src", blobAsDataUrl);
            };

            reader.readAsDataURL(recoveredBlob);
        };

        xhr.open('GET', url);
        xhr.send();
    }
});

非常感谢任何解决方案。

使用ffmpeg.wasm转码的快速演示:

const { createFFmpeg } = FFmpeg;
const ffmpeg = createFFmpeg({
  log: true
});

const transcode = async (webcamData) => {
  const message = document.getElementById('message');
  const name = 'record.webm';
  await ffmpeg.load();
  message.innerHTML = 'Start transcoding';
  await ffmpeg.write(name, webcamData);
  await ffmpeg.transcode(name,  'output.mp4');
  message.innerHTML = 'Complete transcoding';
  const data = ffmpeg.read('output.mp4');

  const video = document.getElementById('output-video');
  video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
  dl.href = video.src;
  dl.innerHTML = "download mp4"
}

fn().then(async ({url, blob})=>{
    transcode(new Uint8Array(await (blob).arrayBuffer()));
})

function fn() {
var recordedChunks = [];

var time = 0;
var canvas = document.getElementById("canvas");

return new Promise(function (res, rej) {
    var stream = canvas.captureStream(60);

    mediaRecorder = new MediaRecorder(stream, {
        mimeType: "video/webm; codecs=vp9"
    });

    mediaRecorder.start(time);

    mediaRecorder.ondataavailable = function (e) {
        recordedChunks.push(event.data);
        // for demo, removed stop() call to capture more than one frame
    }

    mediaRecorder.onstop = function (event) {
        var blob = new Blob(recordedChunks, {
            "type": "video/webm"
        });
        var url = URL.createObjectURL(blob);
        res({url, blob}); // resolve both blob and url in an object

        myVideo.src = url;
        // removed data url conversion for brevity
    }

// for demo, draw random lines and then stop recording
var i = 0,
tid = setInterval(()=>{
  if(i++ > 20) { // draw 20 lines
    clearInterval(tid);
    mediaRecorder.stop();
  }
  let canvas = document.querySelector("canvas");
  let cx = canvas.getContext("2d");
  cx.beginPath();
  cx.strokeStyle = 'green';
  cx.moveTo(Math.random()*100, Math.random()*100);
  cx.lineTo(Math.random()*100, Math.random()*100);
  cx.stroke();
},200)

});
}
<script src="https://unpkg.com/@ffmpeg/ffmpeg@0.8.1/dist/ffmpeg.min.js"></script>

<canvas id="canvas" style="height:100px;width:100px"></canvas>

<video id="myVideo" controls="controls"></video>
<video id="output-video" controls="controls"></video>

<a id="dl" href="" download="download.mp4"></a>

<div id="message"></div>