我们正在开展一个项目,使人们可以使用网络摄像头在聊天室中,并且他们可以当时捕捉某人的摄像头的快照,在其顶部做一些注释,然后像共享照片一样共享修改后的图片。他们自己的网络摄像头(例如共享白板)。

将网络摄像头流捕获到可以编辑的画布元素中相对容易。在页面上找到canvas元素,并在其上执行.getContext('2d'),
使用一个开放库向其中添加编辑工具。像这样从该画布抓取流:

var canvasToSend = document.querySelector('canvas');
var stream = canvasToSend.captureStream(60);
var room = osTwilioVideoWeb.getConnectedRoom();

var mytrack = null;
room.localParticipant.publishTrack(stream.getTracks()[0]).then((publication) => {
    mytrack = publication.track;
    var videoElement = mytrack.attach();
});


这样就可以发布流,但是除非您在画布上绘制其他内容,否则不会发送第一帧。假设您画了2个圆圈,然后点击“分享”,该流将开始,但是除非您画一条线,另一个圆圈或其他任何东西,否则不会显示在收件人的身边。似乎需要更改框架才能发送数据。

我可以通过执行诸如context.fill();之类的操作来使用开发人员工具来强制执行此操作,但是当我尝试在发布功能之后添加此功能时,即使在then()中也没有运气。

关于如何强制这种“刷新”发生的任何想法?

最佳答案

因此,这似乎是预期的行为(因此会使我的FF越野车成为问题)。

the specs关于帧请求算法:


  当frameCaptureRequested为true并绘制画布时,从画布请求一个新的帧。


让我们将重点放在“和已绘制的画布”上。这意味着我们需要这两个条件,并且CaptureStream本身,其frameRate参数变差或类似requestFrame的方法都将frameCaptureRequested标志设置为true时,我们仍然需要新绘画...

 
规范甚至有note声明


  该算法导致捕获的轨道直到画布中的某些内容发生变化才开始。


如果在绘制画布后调用captureStream,Chrome似乎确实会生成一个空的CanvasCaptureMediaStreamTrack。



const ctx = document.createElement('canvas')
  .getContext('2d');
ctx.fillRect(0,0,20,20);
// let's request a stream from before it gets painted
// (in the same frame)
const stream1 = ctx.canvas.captureStream();
vid1.srcObject = stream1;
// now let's wait that a frame ellapsed
// (rAF fires before next painting, so we need 2 of them)
requestAnimationFrame(()=>
  requestAnimationFrame(()=> {
    const stream2 = ctx.canvas.captureStream();
    vid2.srcObject = stream1;
  })
);

<p>stream initialised in the same frame as the drawings (i.e before paiting).</p>
<video id="vid1" controls autoplay></video>
<p>stream initialised after paiting.</p>
<video id="vid2" controls autoplay></video>





因此,要解决此问题,您应该能够通过请求与画布上的第一个图形相同的操作请求流,从而获得带有帧的流,例如上述示例中的stream1

或者,您可以在将其globalCompositeOperation设置为“ copy”以避免透明度问题之后,通过调用ctx.drawImage(ctx.canvas,0,0)在其自身上重绘画布上下文(假设它是2d上下文)。



const ctx = document.createElement('canvas')
  .getContext('2d');
ctx.font = '15px sans-serif';
ctx.fillText('if forced to redraw it should work', 20, 20);
// produce a silent stream again
requestAnimationFrame(() =>
  requestAnimationFrame(() => {
    const stream = ctx.canvas.captureStream();
    forcePainting(stream);
    vid.srcObject = stream;
  })
);
// beware will work only for canvas intialised with a 2D context
function forcePainting(stream) {
  const ctx = (stream.getVideoTracks()[0].canvas ||
      stream.canvas) // FF has it wrong...
    .getContext('2d');
  const gCO = ctx.globalCompositeOperation;
  ctx.globalCompositeOperation = 'copy';
  ctx.drawImage(ctx.canvas, 0, 0);
  ctx.globalCompositeOperation = gCO;
}

<video id="vid" controls autoplay></video>

关于javascript - captureStream()的第一帧未发送,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50929159/

10-12 14:08