在 p5.js 中导出视频

Exporting a video in p5.js

我正在 p5.js 中创建一个简单的动画程序。当用户点击保存按钮时,我想下载动画视频。

我有一个名为 frames 的对象,其中每个键都标记为 frame_1frame_2 等等。与每个键关联的值是构成该帧的 array 线段。

我正在想办法获取这些数据并创建 mp4 视频。 p5.js 有一个内置的 save function,我认为它可能会有帮助,但它本身并不是一个完整的解决方案。我可以将每一帧保存为单独的图像,然后在客户端以某种方式将这些图像拼接在一起,但我还没有找到解决方案。

任何其他方法也很好。唯一的要求是在客户端完成。

正如您在评论中指出的那样,gif 也可以,这是一个解决方案:

下面是一个示例 p5 草图,它使用 gif.js.

录制 canvas 动画并将其转换为 gif。

Works in browsers supporting: Web Workers, File API and Typed Arrays.

我提供了这段代码,这样您就可以了解如何使用这个库,因为没有为它提供太多文档,而且我自己也很难搞清楚。

var cnv;

var gif, recording = false;

function setup() {
    cnv = createCanvas(400, 400);

    var start_rec = createButton("Start Recording");
    start_rec.mousePressed(saveVid);

    var stop_rec = createButton("Stop Recording");
    stop_rec.mousePressed(saveVid);

    start_rec.position(500, 500);
    stop_rec.position(650, 500);

    setupGIF();
}

function saveVid() {
    recording = !recording;
    if (!recording) {
        gif.render();
    }
}
var x = 0;
var y = 0;

function draw() {
    background(51);
    fill(255);
    ellipse(x, y, 20, 20);
    x++;
    y++;

    if (recording) {
        gif.addFrame(cnv.elt, {
            delay: 1,
            copy: true
        });
    }
}

function setupGIF() {
    gif = new GIF({
        workers: 5,
        quality: 20
    });
    gif.on('finished', function(blob) {
        window.open(URL.createObjectURL(blob));
    });
}

更多信息:

此草图在您单击 start_rec 时开始记录帧,并在您单击 stop_rec 时停止,在您的草图中,您可能希望以不同方式控制内容,但请记住 addFrame只添加一帧到gif所以你需要在draw函数中调用它来添加多帧,你可以传入一个ImageElement,一个CanvasElement或一个CanvasContext以及其他可选参数。

gif.on 函数中,您可以指定一个回调函数来对 gif 执行任何您喜欢的操作。

如果您想微调 gif 的设置,例如 qualityrepeatbackground,您可以阅读更多内容 here。希望这对您有所帮助!

由于 p5.js 是建立在 Canvas API 之上的,在现代浏览器中,您可以使用 MediaRecorder 来完成这项工作。

const btn = document.querySelector('button'),
  chunks = [];

function record() {
  chunks.length = 0;
  let stream = document.querySelector('canvas').captureStream(30),
    recorder = new MediaRecorder(stream);
  recorder.ondataavailable = e => {
    if (e.data.size) {
      chunks.push(e.data);
    }
  };
  recorder.onstop = exportVideo;
  btn.onclick = e => {
    recorder.stop();
    btn.textContent = 'start recording';
    btn.onclick = record;
  };
  recorder.start();
  btn.textContent = 'stop recording';
}

function exportVideo(e) {
  var blob = new Blob(chunks);
  var vid = document.createElement('video');
  vid.id = 'recorded'
  vid.controls = true;
  vid.src = URL.createObjectURL(blob);
  document.body.appendChild(vid);
  vid.play();
}
btn.onclick = record;

// taken from pr.js docs
var x, y;

function setup() {
  createCanvas(300, 200);
  // Starts in the middle
  x = width / 2;
  y = height;
}

function draw() {
  background(200);

  // Draw a circle
  stroke(50);
  fill(100);
  ellipse(x, y, 24, 24);

  // Jiggling randomly on the horizontal axis
  x = x + random(-1, 1);
  // Moving up at a constant speed
  y = y - 1;

  // Reset to the bottom
  if (y < 0) {
    y = height;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/p5.min.js"></script>
<button>start recording</button><br>

ccapture 与 p5.js 配合使用可以很好地实现记录 canvas.

上显示的内容的目标

这是 demo 与 p5.js 一起使用的 ccapture。 demo自带源码

此方法不会输出延迟的视频,因为它没有记录您在屏幕上看到的内容,这可能会延迟。相反,它将每一帧写入视频并告诉视频以固定帧速率播放。所以即使只计算一帧需要几秒钟,输出的视频也会流畅播放,不会出现帧与帧之间的任何延迟。

但是,有一点需要注意。此方法仅适用于 Chrome.