воспроизведение записанного потока с помощью MediaRecorder() из с помощью canvas.captureStream() рендеринг в firefox, chromium по-разному

#javascript #firefox #chromium #capture #mediarecorder-api

#javascript #firefox #chromium #захват #mediarecorder-api

Вопрос:

Используя оригинал javascript в MediaRecorder-examples/record-canvas-to-video.js

Требования к программному обеспечению

  • Firefox 45. Это техническая демонстрация Firefox. Поэтому он может не работать в вашем браузере, если он не реализует то, что мы демонстрируем. На момент написания (январь 2016) вам необходимо загрузить либо 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);
  }

};
  

выдает ошибки в chromium 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.

Настройка javascript для использования в chromium путем нажатия Blob на dataavailable событие MediaRecorder в массив, затем конкатенации больших двоичных объектов в stop событии

 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, отображаются с очевидной минимальной, хотя и заметной задержкой между объединенными большими двоичными объектами.

Как мы можем визуализировать то же визуальное воспроизведение canvas.captureStream() записанного с использованием MediaRecorder() <video> элемента at?

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

Комментарии:

1. Пример, на который вы ссылаетесь, устарел (см. MDN для более современного примера , который также работает с Chrome), поэтому я думаю, вы можете сократить размер своего вопроса вдвое. s / blobs / chunks/

2. @jib Да, хотя заметили ли вы разницу в воспроизведении записанного canvas между firefox и chromium, chrome?

Ответ №1:

Здесь вы управляете анимацией из основного потока JS, поэтому возможно, что другие действия JS основного потока, такие как запуск ondataavailable обратного вызова, могут нарушить синхронизацию настолько, чтобы быть заметными.

Попробуйте опустить частоту кадров (60) в canvas.captureStream() вызове.

MDN говорит: «Если не задано, новый кадр будет записываться каждый раз при изменении холста; если установлено значение 0, будет записан один единственный кадр».

Мы надеемся, что это должно сделать вывод более невосприимчивым к таким прерываниям за счет незначительного сокращения его длины.

Вы также можете указать временной интервал с помощью метода start, например recorder.start(2000) , чтобы ограничить время срабатывания dataavailable события, чтобы избежать прерываний.

Комментарии:

1. Пропуск 60 в качестве параметра, по canvas.captureStream() -видимому, возвращает ожидаемый результат.