Как правильно записать поток с холста? - PullRequest
0 голосов
/ 26 сентября 2018

СИТУАЦИЯ:

Мне нужно сделать следующее:

  • Получить видео с <video> и воспроизводить внутри <canvas>

  • Запись потока с холста в виде BLOB-объекта

Вот и все.Первая часть в порядке.Для второй части мне удалось записать Blob, проблема в том, что Blob пуст.

ВИД:

<video id="video" controls="true" src="http://upload.wikimedia.org/wikipedia/commons/7/79/Big_Buck_Bunny_small.ogv"></video>
<canvas id="myCanvas" width="532" height="300"></canvas>

КОД:

// Init
console.log(MediaRecorder.isTypeSupported('video/webm')) // true
const canvas = document.querySelector("canvas")
const ctx = canvas.getContext("2d")
const video = document.querySelector("video")

// Start the video in the player
video.play()

// On play event - draw the video in the canvas
video.addEventListener('play', () => {
  function step() {
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
    requestAnimationFrame(step)
  }
  requestAnimationFrame(step);

  // Init stream and recorder
  const stream = canvas.captureStream()
  const recorder = new MediaRecorder(stream, {
    mimeType: 'video/webm',
  });

  // Get the blob data when is available
  let allChunks = [];
  recorder.ondataavailable = function(e) {
    console.log({e}) // img1
    allChunks.push(e.data);
  }

  // Start to record
  recorder.start()

  // Stop the recorder after 5s and check the result
  setTimeout(() => {
    recorder.stop()
    const fullBlob = new Blob(allChunks, { 'type' : 'video/webm' });
    const downloadUrl = window.URL.createObjectURL(fullBlob)
    console.log({fullBlob}) // img2
  }, 5000);
})

РЕЗУЛЬТАТ:

Это console.log события ondataavailable:

enter image description here

Это console.log BLOB-объекта:

enter image description here

FIDDLE:

Вот JsFiddle.Вы можете проверить результаты в консоли:

https://jsfiddle.net/1b7v2pen/

ПОВЕДЕНИЕ БРАУЗЕРОВ:

Такое поведение (размер данных BLOB-объектов: 0) происходитна Хроме и Опере.
На Firefox он ведет себя немного иначе.Записывает очень маленькое видео Blob (725 байт).Продолжительность видео составляет 5 секунд, как и должно быть, но это просто черный экран.

ВОПРОС:

Как правильно записать поток изхолст?
Что-то не так в коде?
Знаете ли вы, почему Blob вышел пустым?

Спасибо!

1 Ответ

0 голосов
/ 26 сентября 2018

MediaRecorder.stop() является своего рода асинхронным методом.

В алгоритме stop существует вызов requestData , который сам поставит в очередь задачу для запуска события dataavailable с текущимдоступные данные с момента последнего такого события.

Это означает, что синхронно после того, как вы вызвали MediaRecorder # stop () , последние захваченные данные еще не будут частью вашего allChunks массива.Они станут не такими длинными после этого (обычно в одном и том же цикле событий).

Поэтому, когда вы собираетесь сохранять записи, сделанные из MediaRecorder, обязательно всегда собирайте последний BLOB-объект из MediaRecorder.Событие onstop, которое будет сигнализировать о том, что MediaRecorder действительно завершен, запустило свое последнее событие dataavailable и все хорошо.

И одна вещь, которую я пропустил приВо-первых, вы запрашиваете междоменное видео.В результате этого без правильного запроса перекрестного происхождения ваш холст (и MediaElement) будут испорчены, поэтому ваш MediaStream будет отключен.

Поскольку видео, которое вы пытаетесь запросить, получено из Викимедиа, вы можете просто запроситьон является ресурсом разных источников, но для других ресурсов вы должны быть уверены, что сервер настроен на разрешение этих запросов.

const canvas = document.querySelector("canvas")
const ctx = canvas.getContext("2d")
const video = document.querySelector("video")

// Start the video in the player
video.play()

// On play event - draw the video in the canvas
video.addEventListener('play', () => {
  function step() {
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
    requestAnimationFrame(step)
  }
  requestAnimationFrame(step);
  
  // Init stream and recorder
  const stream = canvas.captureStream()
  const recorder = new MediaRecorder(stream, {
    mimeType: 'video/webm',
  });

  // Get the blob data when is available
  let allChunks = [];
  recorder.ondataavailable = function(e) {
    allChunks.push(e.data);
  }
  recorder.onstop = (e) => {
    const fullBlob = new Blob(allChunks, { 'type' : 'video/webm' });
    const downloadUrl = window.URL.createObjectURL(fullBlob)
    console.log({fullBlob})
    console.log({downloadUrl})
  }

  // Start to record
  recorder.start()

  // Stop the recorder after 5s and check the result
  setTimeout(() => {
    recorder.stop()
  }, 5000);
})
<!--add the 'crossorigin' attribute to your video -->
<video id="video" controls="true" src="https://upload.wikimedia.org/wikipedia/commons/7/79/Big_Buck_Bunny_small.ogv" crossorigin="anonymous"></video>
<canvas id="myCanvas" width="532" height="300"></canvas>

Кроме того, я не могу не отметить, что если вы не делаете никаких специальных рисунков со своего холста, вы можете сохранитьнепосредственно к источнику видео или, по крайней мере, напрямую записывать captureStream MediaStream.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...