3

我有一个从getDisplayMedia()返回的实时屏幕捕获媒体流,以及一个从getUserMedia()
返回的实时网络摄像头媒体流。

我目前在屏幕共享视频上渲染网络摄像头视频,以创建画中画效果:

在此处输入图像描述

我想将它们混合/组合成一个视频流,以便在单个 HTML 视频元素中呈现它。
我想让两个流都保持活跃和直播,就好像它们是两个独立的视频,呈现两个不同的媒体流一样。
我还需要保持流位置 - 保持网络摄像头流较小并位于屏幕共享流的顶部。保持原始分辨率和比特率对我来说也很重要。

我怎样才能做到这一点?

4

2 回答 2

4

您可以在 HTMLCanvasElement 上绘制两个视频流,然后从该 HTMLCanvasElement 调用其captureStream方法创建一个 MediaStream。

要绘制这两个视频流,您必须在 <video> 元素中读取它们,并将drawImage()这些 <video> 元素以定时循环的方式读取到画布上(例如requestAnimationFrame,可用于此定时循环)。

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,因此现场演示存在故障。

于 2021-01-05T05:38:41.843 回答
1

我尝试在画布上渲染,但每当我更改/最小化我的网络应用程序选项卡时,刷新率都会下降。我能够使用audioTimerLoop解决这个问题。但它仍然没有在firefox上工作。
由于我现在仅限于 chrome,因此我使用PictureInPicture api 将 userMedia 显示为 PiP,然后只记录 screenMedia。这让用户可以调整他们在画布方法中固定的凸轮视频坐标。

PS 为了获得点子模式。我在屏幕上显示了 userMedia 并将其不透明度设置为 0%,并创建了一个按钮来切换它。

于 2021-08-20T08:49:32.023 回答