Как смешать / объединить несколько медиапотоков WebRTC (снимок экрана + веб-камера) в один поток?

У меня есть медиапоток для захвата экрана в реальном времени, возвращенный из getDisplayMedia (),
и поток мультимедиа с веб-камеры, возвращенный из getUserMedia ().

В настоящее время я визуализирую видео с веб-камеры поверх видео для демонстрации экрана, чтобы создать эффект «картинка в картинке»:

введите описание изображения здесь

Я хочу смешать / объединить их в один видеопоток, чтобы отобразить его внутри одного видеоэлемента HTML.
Я хочу, чтобы оба потока были активными и живыми, как если бы они были двумя отдельными видео, отображающими два разных медиапотока. .
Мне также нужно поддерживать позиции потоков - чтобы поток с веб-камеры оставался небольшим и поверх потока общего доступа к экрану. Для меня также очень важно сохранить исходное разрешение и битрейт.

Как я могу это сделать?


person amiregelz    schedule 04.01.2021    source источник


Ответы (1)


Вы можете нарисовать оба видеопотока на HTMLCanvasElement, а затем создать MediaStream из этого HTMLCanvasElement, вызвав его метод captureStream.

Чтобы нарисовать два видеопотока, вам нужно будет прочитать их в элементах ‹video› и _ 1_ эти ‹video› элементы на холсте в заданном цикле (например, _ 2_ может использоваться для этого временного цикла).

async function getOverlayedVideoStreams( stream1, stream2 ) {
  // prepare both players
  const vid1 = document.createElement("video");
  const vid2 = document.createElement("video");
  vid1.muted = vid2.muted = true;
  vid1.srcObject = stream1;
  vid2.srcObject = stream2;
  await Promise.all( [
    vid1.play(),
    vid2.play()
  ] );
  // craete the renderer
    const canvas = document.createElement("canvas");
  let w = canvas.width = vid1.videoWidth;
  let h = canvas.height = vid1.videoHeight;
  const ctx = canvas.getContext("2d");

  // MediaStreams can change size while streaming, so we need to handle it
  vid1.onresize = (evt) => {
    w = canvas.width = vid1.videoWidth;
    h = canvas.height = vid1.videoHeight;
  };
  // start the animation loop
  anim();
  
  return canvas.captureStream();
  
  function anim() {
    // draw bg video
        ctx.drawImage( vid1, 0, 0 );
    // caculate size and position of small corner-vid (you may change it as you like)
    const cam_w = vid2.videoWidth;
    const cam_h = vid2.videoHeight;
    const cam_ratio = cam_w / cam_h;
    const out_h = h / 3;
    const out_w = out_h * cam_ratio;
    ctx.drawImage( vid2, w - out_w, h - out_h, out_w, out_h );
    // do the same thing again at next screen paint
    requestAnimationFrame( anim );
  }
}

Живая демонстрация как сбой, поскольку StackSnippets не поддерживает API захвата.

person Kaiido    schedule 05.01.2021
comment
Спасибо за ответ! Для меня очень важно сохранить разрешение и битрейт исходного потока. Могу ли я сделать какие-либо оптимизации при рендеринге холста, которые идеально подходят для потокового совместного использования экрана / веб-камеры? - person amiregelz; 05.01.2021
comment
Нет. Если это так важно, отправьте оба потока по отдельности, поскольку они могут иметь разные битрейты. - person Kaiido; 05.01.2021