5

我从canvasthrough获取帧canvas.getDataURL()

但是,现在我有一组 png 图像,但我想要一个视频文件。

我该怎么做呢?

var canvas = document.getElementById("mycanvaselementforvideocapturing");
var pngimages = [];
...
setInterval(function(){pngimages.push(canvas.toDataURL())}, 1000);
4

2 回答 2

11

对于完整的浏览器支持方式,您必须将图像批次发送到服务器,然后使用一些服务器端程序进行编码。

FFmpeg 或许可以做到。

但在最新的浏览器中,该canvas.captureStream方法已经实现。它将您的画布绘图转换为 webm 视频流,可使用MediaRecorder. 尽管如此,所有这些都还没有稳定下来,只能在最新版本的浏览器中使用,可能在用户的偏好中设置了一些标志(例如,chrome 需要“实验性 Web 平台”之一)。

var cStream,
  recorder,
  chunks = [];

rec.onclick = function() {
  this.textContent = 'stop recording';
  // set the framerate to 30FPS
  var cStream = canvas.captureStream(30);
  // create a recorder fed with our canvas' stream
  recorder = new MediaRecorder(cStream);
  // start it
  recorder.start();
  // save the chunks
  recorder.ondataavailable = saveChunks;

  recorder.onstop = exportStream;
  // change our button's function
  this.onclick = stopRecording;
};

function saveChunks(e) {

  chunks.push(e.data);

}

function stopRecording() {

  recorder.stop();

}


function exportStream(e) {
  // combine all our chunks in one blob
  var blob = new Blob(chunks)
    // do something with this blob
  var vidURL = URL.createObjectURL(blob);
  var vid = document.createElement('video');
  vid.controls = true;
  vid.src = vidURL;
  vid.onended = function() {
    URL.revokeObjectURL(vidURL);
  }
  document.body.insertBefore(vid, canvas);
}

// make something move on the canvas
var x = 0;
var ctx = canvas.getContext('2d');

var anim = function() {
  x = (x + 2) % (canvas.width + 100);
  // there is no transparency in webm,
  // so we need to set a background otherwise every transparent pixel will become opaque black
  ctx.fillStyle = 'ivory';
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = 'black';
  ctx.fillRect(x - 50, 20, 50, 50)
  requestAnimationFrame(anim);
};
anim();
<canvas id="canvas" width="500" height="200"></canvas>
<button id="rec">record</button>

而且由于您要求一种向该视频添加音频的方法,请注意您可以cStream.addTrack(anAudioStream.getAudioTracks()[0]);在调用之前使用new MediaRecorder(cStream),但这目前仅适用于 chrome,FF 似乎在 MediaRecorder 中有一个错误,使其仅记录带有轨道的流被定义为... FF 的解决方法是调用new MediaStream([videoTrack, audioTrack]);

[非常感谢@jib 让我知道如何实际使用它...]

编辑:video.onend-->video.onended

于 2016-08-13T05:25:47.737 回答
1

Kaiido 答案中的MediaRecorder+canvas.captureStream方法绝对是目前要走的路 - 不幸的是,截至撰写本文时,它仅在 Chrome 和 Firefox 中受支持。

当浏览器采用 webp 编码支持(目前只有 Chrome 支持)时,另一种可行的方法是:

let frames = []; // <-- frames must be *webp* dataURLs
let webmEncoder = new Whammy.Video(fps); 
frames.forEach(f => webmEncoder.add(f));
let blob = await new Promise(resolve => webmEncoder.compile(false, resolve));
let videoBlobUrl = URL.createObjectURL(blob);

它使用whammy库将一堆 webp 图像加入到 webm 视频中。在支持 webp 编码的浏览器中,您可以编写canvas.toDataURL("image/webp")以从画布获取 webp dataURL。是 Firefox webp 支持的相关错误报告。

在撰写本文时,一种跨浏览器方法似乎是使用libwebp.js将输出的 png dataURLs 转换canvas.toDataURL()为 webp 图像,然后将它们输入 whammy 编码器以获得最终的 webm 视频。不幸的是,png--> webp 编码过程非常慢(我的笔记本电脑上几秒钟的视频需要几分钟)。

编辑:我发现使用MediaRecorder/captureStream方法,与 whammy 方法相比,您最终会得到低质量的输出视频。因此,除非有某种方法可以控制捕获流的质量,否则该whammy方法似乎是最好的方法,而其他两种方法则作为后备。有关更多详细信息,请参阅此问题。使用此代码段来检测浏览器是否支持webp编码(因此支持 whammy 方法):

let webPEncodingIsSupported = document.createElement('canvas').toDataURL('image/webp').startsWith('data:image/webp');
于 2018-09-17T12:31:48.480 回答