Есть ли способ отправить видеоданные из видеотега/MediaStream в OffscreenCanvas?

В основном я хочу иметь возможность эффективно выполнять этот же код:


const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');

const draw = () => {
  context.drawImage(video, 0, 0);
  requestAnimationFrame(draw);
}

video.onplay = () => {
  requestAnimationFrame(draw);
}

только с использованием закадрового холста. Я могу отправлять изображения через сообщения рабочему, на котором находится закадровый холст, но не видео, поскольку оно напрямую связано с HTMLElement. Есть ли в настоящее время способ каким-то образом отображать видеоданные или MediaStream на закадровом холсте?


person Jacob Greenway    schedule 25.06.2019    source источник
comment
Вы когда-нибудь находили решение этого? У меня такой же вопрос   -  person hoodsy    schedule 05.03.2020


Ответы (1)


Вы можете отправлять кадры видео на OffscreenCanvas в Web Worker, изменив свой скрипт со следующими изменениями:

const worker = new Worker('my-worker.js');
const video = document.getElementById('video');
const stream = video.captureStream();
const [track] = stream.getVideoTracks();
const imageCapture = new ImageCapture(track);
const canvas = document.getElementById('canvas');
const offscreen = canvas.transferControlToOffscreen();

worker.postMessage({ offscreen }, [offscreen]);

const draw = () => {
  imageCapture.grabFrame().then(imageBitmap => {
    worker.postMessage({ imageBitmap }, [imageBitmap]);
  });

  requestAnimationFrame(draw);
};

video.onplay = () => {
  requestAnimationFrame(draw);
};

my-worker.js

let canvas;
let context;

addEventListener('message', event => {
  if (event.data.offscreen) {
    canvas = event.data.offscreen;
    context = canvas.getContext('2d');
  } else if (event.data.imageBitmap && context) {
    context.drawImage(event.data.imageBitmap, 0, 0);
    // do something with frame
  }
});

Рекомендации

person Patrick Roberts    schedule 25.06.2019
comment
Спасибо за ответ, но я думаю, что искал способ разгрузить вызовы requestAnimationFrame с помощью закадрового холста, поскольку requestAnimationFrame дросселируется браузерами, когда вкладка размыта. Это решает мой первоначальный вопрос, но есть ли способ вывести видео на закадровый холст без вызовов timer/requestAnimationFrame? - person Jacob Greenway; 25.06.2019
comment
@JacobGreenway зависит от src видео. Но requestAnimationFrame() также блокируется в веб-воркерах, когда вкладка, которая их породила, теряет фокус, поэтому вам нужно немного поумнеть, чем просто запустить исходный код в веб-воркере. - person Patrick Roberts; 25.06.2019
comment
К сожалению, по-прежнему поддерживается только в браузерах Blink, для FF вы можете использовать createImageBitmap, передаваемый потребителю ‹video›. @JacobGreenway для вашей первоначальной проблемы, вас может заинтересовать этот мой старый взлом что позволяет иметь нерегулируемый цикл, однако браузер по-прежнему будет ограничивать многие вещи, поэтому его полезность весьма ограничена... - person Kaiido; 25.06.2019
comment
какая польза от подобного, если воркер не обрабатывает анимацию? - person hoodsy; 05.03.2020
comment
@hoodsy grabFrame() и postMessage(), вызываемые с помощью объекта Transferable, не являются очень дорогие вычисления в потоке DOM, поэтому у него есть много свободного времени для обработки пользовательских событий и перерисовок, в то время как дорогостоящая работа drawImage() и других методов контекста холста переносится в рабочий поток, где это не оказывает негативного влияния на скорость отклика. страница интернета. - person Patrick Roberts; 15.03.2021
comment
@PatrickRoberts transferControlToOffscreen имеет низкую поддержку браузеров - person Alexufo; 25.06.2021