1

使用javascript原件MediaRecorder-examples/record-canvas-to-video.js

软件要求

  • Firefox 45。这是一个 Firefox 技术演示。因此,如果它没有实现我们正在演示的内容,它可能无法在您的浏览器上运行。在撰写本文时(2016 年 1 月),您需要下载 Firefox Developer Edition 或 Firefox Nightly。
window.onload = function () {
  var video = document.getElementById('video');
  var canvas = document.getElementById('canvas');
  var width = canvas.width;
  var height = canvas.height;
  var capturing = false;

  video.width = width;
  video.height = height;

  // We need the 2D context to individually manipulate pixel data
  var ctx = canvas.getContext('2d');

  // Start with a black background
  ctx.fillStyle = '#000';
  ctx.fillRect(0, 0, width, height);

  // Since we're continuously accessing and overwriting the pixels
  // object, we'll request it once and reuse it across calls to draw()
  // for best performance (we don't need to create ImageData objects
  // on every frame)
  var pixels = ctx.getImageData(0, 0, width, height);
  var data = pixels.data;
  var numPixels = data.length;

  var stream = canvas.captureStream(15);
  var recorder = new MediaRecorder(stream);

  recorder.addEventListener('dataavailable', finishCapturing);

  startCapturing();
  recorder.start();

  setTimeout(function() {
    recorder.stop();
  }, 2000);


  function startCapturing() {
    capturing = true;
    draw();
  }


  function finishCapturing(e) {
    capturing = false;
    var videoData = [ e.data ];
    var blob = new Blob(videoData, { 'type': 'video/webm' });
    var videoURL = URL.createObjectURL(blob);
    video.src = videoURL;
    video.play();
  }


  function draw() {
    // We don't want to render again if we're not capturing
    if(capturing) {
      requestAnimationFrame(draw);
    }
    drawWhiteNoise();
  }


  function drawWhiteNoise() {
    var offset = 0;

    for(var i = 0; i < numPixels; i++) {
      var grey = Math.round(Math.random() * 255);

      // The data array has pixel values in RGBA order
      // (Red, Green, Blue and Alpha for transparency)
      // We will make R, G and B have the same value ('grey'),
      // then skip the Alpha value by increasing the offset,
      // as we're happy with the opaque value we set when painting
      // the background black at the beginning
      data[offset++] = grey;
      data[offset++] = grey;
      data[offset++] = grey;
      offset++; // skip the alpha component
    }

    // And tell the context to draw the updated pixels in the canvas
    ctx.putImageData(pixels, 0, 0);
  }

};

在铬 55 处产生错误

Uncaught (in promise) DOMException: The play() request was interrupted by a new load request.

Failed to load resource: the server responded with a status of 416 (Requested Range Not Satisfiable)

虽然在 Firefox 52 处返回预期结果。

通过将事件推送到数组,然后在事件中连接 blob 来调整在铬javascript上的使用BlobdataavailableMediaRecorderstop

window.onload = function () {
  var blobs = [];
  var video = document.getElementById('video');
  var canvas = document.getElementById('canvas');
  var width = canvas.width;
  var height = canvas.height;
  var capturing = false;

  video.width = width;
  video.height = height;

  // We need the 2D context to individually manipulate pixel data
  var ctx = canvas.getContext('2d');

  // Start with a black background
  ctx.fillStyle = '#000';
  ctx.fillRect(0, 0, width, height);

  // Since we're continuously accessing and overwriting the pixels
  // object, we'll request it once and reuse it across calls to draw()
  // for best performance (we don't need to create ImageData objects
  // on every frame)
  var pixels = ctx.getImageData(0, 0, width, height);
  var data = pixels.data;
  var numPixels = data.length;

  var stream = canvas.captureStream(15);
  var recorder = new MediaRecorder(stream);

  recorder.addEventListener('dataavailable', finishCapturing);
  recorder.addEventListener('stop', function(e) {
    video.oncanplay = video.play;
    video.src = URL.createObjectURL(new Blob(blobs, {type:"video/webm"}));
  });
  startCapturing();
  recorder.start();

  setTimeout(function() {
        capturing = false;
    recorder.stop();
  }, 2000);


  function startCapturing() {
    capturing = true;
    draw();
  }


  function finishCapturing(e) {
    blobs.push(e.data);
  }


  function draw() {
    // We don't want to render again if we're not capturing
    if(capturing) {
      requestAnimationFrame(draw);
    }
    drawWhiteNoise();
  }


  function drawWhiteNoise() {
    var offset = 0;

    for(var i = 0; i < numPixels; i++) {
      var grey = Math.round(Math.random() * 255);

      // The data array has pixel values in RGBA order
      // (Red, Green, Blue and Alpha for transparency)
      // We will make R, G and B have the same value ('grey'),
      // then skip the Alpha value by increasing the offset,
      // as we're happy with the opaque value we set when painting
      // the background black at the beginning
      data[offset++] = grey;
      data[offset++] = grey;
      data[offset++] = grey;
      offset++; // skip the alpha component
    }

    // And tell the context to draw the updated pixels in the canvas
    ctx.putImageData(pixels, 0, 0);
  }

};

类似于 firefox 渲染记录的流。

然而,在 firefox 和 chromium 上播放视频的调整明显最小,但在连接的 blob 之间存在明显的延迟。

我们如何渲染使用at元素canvas.captureStream()录制的相同视觉回放?MediaRecorder()<video>

plnkr http://plnkr.co/edit/KgGpkCJRvPG2T2Jy4wyH?p=preview

4

1 回答 1

1

您正在从此处的主 JS 线程驱动动画,因此其他主线程 JS 活动(如ondataavailable回调触发)可能会破坏足够明显的时间。

canvas.captureStream()尝试从调用中省略 (60) 帧速率。

MDN说:“如果不设置,则每次画布更改时都会捕获一个新帧;如果设置为 0,则将捕获一个单帧。”

这有望使输出更不受此类中断的影响,但代价是略微缩短其长度。

您还可以使用 start 方法指定时间例如限制事件何时触发以避免中断。recorder.start(2000)dataavailable

于 2016-10-09T15:27:53.150 回答