【问题标题】:Exporting a video in p5.js在 p5.js 中导出视频
【发布时间】:2017-02-24 11:52:47
【问题描述】:

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

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

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

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

【问题讨论】:

  • 发送图像流数据到ffmpeg不是一个选项吗?如果可以接受的话,将画布帧转换为动画 gif 也会少很多麻烦
  • @MasterYushi 现在 gif 将是一个非常好的选择。没想到。

标签: javascript video processing p5.js


【解决方案1】:

由于 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>

【讨论】:

  • 这真的很棒。我想知道为什么我可以立即下载视频?看来我需要等待它...创建?加载?
【解决方案2】:

ccapture 与 p5.js 配合得很好,可以实现记录画布上显示内容的目标。

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

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

但是,有一个警告。此方法仅适用于 Chrome。

【讨论】:

  • 很高兴有一个 p5 编辑器,但代码不再工作 webm 代码有问题
  • @lesolorzanov 感谢您的试用。我只是累了(2020 年 4 月 18 日)。它适用于 Chrome。该方法仅适用于 Chrome。您使用的是 Chrome 吗?
  • 是的,我正在使用 Chrome。我正在使用我自己的项目,它的结构和文件与你的相同,但是一旦我按下“开始录制”按钮,动画就会冻结,并且我在 webm-writer 和 ccapture 中遇到了很多问题。
  • @lesolorzanov 抱歉。似乎有些问题。我只是简化了代码。希望它现在可以工作。
  • 我最终在 Blender 中制作动画,呵呵,谢谢,我会看看
【解决方案3】:

正如您在 cmets 中指定的 gif 也可以使用,这里有一个解决方案:

下面是一个示例 p5 草图,它使用 gif.js 记录画布动画并将其转换为 gif。

适用于支持:Web Workers、File API 和 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 函数中调用它来添加多个帧,您可以传入ImageElementCanvasElementCanvasContext 以及其他可选参数。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多