导出p5.js中的视频

时间:2017-02-24 11:52:48

标签: javascript video processing p5.js

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

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

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

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

4 个答案:

答案 0 :(得分:8)

由于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;
  }
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/p5.min.js"></script>
<button>start recording</button><br>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

当您遇到不知道如何接近的问题时,您需要做的第一件事就是将问题分解为更小的子问题。然后你可以一次一个地处理这些小问题。推荐阅读:How to Program

我会说你所描述的并不是微不足道的。 JavaScript具有许多内置的安全功能,使得操作本地文件变得困难 - 毕竟,您不希望任何访问过的网站都能访问您的硬盘。

一种解决方案是将图像发送到服务器并让服务器创建视频。但是如果你刚刚开始使用P5.js,创建服务器将是一项巨大的工作。

基本的Google搜索this library,它似乎支持将画布动画(这是P5.js)保存到视频中。我还发现this question导致this library

另一种选择是切换到常规处理并将动画导出为应用程序而不是webapp。然后你可以用本地文件做任何你想做的事情。但是你失去了嵌入浏览器的能力。

答案 2 :(得分:1)

正如您在评论中指出的那样,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仅添加draw一个框架到gif所以你需要在ImageElement函数中调用它来添加多个框架,你可以传入CanvasElementCanvasContextgif.on以及其他可选参数。

quality函数中,您可以使用gif指定回调函数来执行任何操作。

如果您想微调gif的设置,例如repeatbackgroundconst url = 'https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png?' + Math.random(); // the same for both requests, but different for each snippets function requestData(cb){ let xhr = new XMLHttpRequest(), startTime; xhr.open('get', url); xhr.onload = e => { console.log(performance.now() - startTime); if(cb){ cb(); } } startTime = performance.now(); xhr.send(); } requestData(requestData);,您可以阅读更多here。希望这有帮助!

答案 3 :(得分:0)

ccapture与p5.js一起很好地实现了记录画布上显示内容的目的。

这是demo的捕获与p5.js一起使用的功能。该示例附带了源代码。

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

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