在WebRTC中创建和传输自定义媒体流

7

我想将canvas元素作为webrtc通信视频部分的mediastreamsource,任何方向都会很有帮助。我查遍了网络,发现没有多少资源讨论这个话题,您能帮我吗?

*长背景故事*

问题在于,我不能直接从摄像头发送视频,因为需要在显示之前处理视频(一些图像处理内容不在此问题范围内)。

以前,在另一个对等方的浏览器上,我没有直接使用<video>标签显示视频,而是在隐藏的canvas元素上进行了一些处理,然后将详细信息复制到另一个canvas中(我使用了settimeout来进行绘画,这给人们实时视频的错觉)。

现在,客户要求在传输视频之前进行处理,因此我使用webrtc直接传递音频流(先前通过webrtc发送音频和视频)。对于视频流,我有两个解决方案:

步骤:

  1. 在本地对等方上处理视频,绘制到隐藏的canvas上(容易实现)。

  2. 使用超时定期捕获图像数据并传输:
    a) 使用websockets(经过服务器),效果非常糟糕,浏览器最终崩溃。
    b) 使用RTCDataChannel,性能更好,但有时会无缘无故失败。同时还会存在其他问题(例如,发送jpeg而不是webp会额外使用带宽)。

另一个主要问题是,由于我使用了timeout:当我切换选项卡时,对方屏幕的帧率会降低。

所以,有没有办法可以让我使用隐藏的canvas作为mediastreamsource,而不是手动实现呢?


1
你能限制使用Firefox吗?你可以尝试使用mozCaptureStreamUntilEnded来实现某些内容。或者,另一种方法是通过某种类似于MCU(如Janus-Gateway或Licode的Erizo)的中央控制单元中继媒体流。 - Benjamin Trent
不幸的是,它需要支持frefox和chrome。我想过使用mozCaptureStreamUntilEnded方法,但在firefox中也需要预先录制媒体,对吧? - mido
可能有一些东西可以被拼凑在一起,仍然使用超时来捕获画布,这是Jesup在他的回答中提到的。 - Benjamin Trent
2个回答

3

mozCaptureStreamUntilEnded将成为WG提议的基础,该提议由Martin Thompson负责,用于直接连接到MediaStream。根据这里的评论,在Firefox中的解决方法是从从MediaStream捕获的画布中使用mozCaptureStreamUntilEnded。这是一种不太美观的序列,这也是我们将允许直接将

请注意,将mozCaptureStream(UntilEnded)提供给PeerConnection曾经有问题(部分原因是迄今为止它不是标准的)。它已经在Firefox 36中得到修复(将在6周内发布;下周进入Beta)。参见Bug 1097224和Bug 1081409。

在Chrome和Firefox上,一个非常hacky的方法是将视频放在窗口中,然后对窗口进行屏幕捕获。我不建议这样做,因为它需要屏幕共享权限,选择窗口等。

Chrome(或Firefox)的唯一其他选项是将视频帧保存为JPEG,并通过DataChannel发送。实际上是Motion-JPEG,但由JS运行。帧速率、质量(和延迟)会受到影响。您可能需要使用不可靠的通道,因为在错误时可以丢弃帧并解码下一帧(毕竟它是MJPEG)。此外,如果延迟过高,请减小帧大小!您需要估计端到端延迟;最好的方法是通过数据通道将解码时间反馈给发送者,并使用该数据包的接收时间估计延迟。您更关心延迟的变化而不是绝对值!!


1
当你询问WebRTC问题时,我总是很高兴,因为我们知道我们获得了准确的信息:)。 - Benjamin Trent
@jesup,使用数据通道时我遇到了两个问题:一是如果对等端更改选项卡,则超时调用会变慢,因此视频从10 fps减慢到1-2 fps,并且由于某种原因(无法调试),一段时间后,通道(readyState仍为“open”)就停止传输数据,最糟糕的是,没有任何指示表明它已停止(超时函数仍然被调用,我必须查看其他对等端屏幕并找出它已停止)。 - mido
@mido22 在JS中使用setTimeout调用时,当焦点转移到另一个选项卡时,所有浏览器都会减少或停止(或先减少再停止)调用频率。这是非常有意的。您可以尝试使用Worker的形式,但我不确定是否有效。您通常可以获得其他事件,因此您可能能够获取反向流量来驱动捕获(虽然不完美,但可能有效-让客户端通过setTimeout发送“给我一帧”,并在接收到这些帧时抓取它们。好的副作用:如果客户端停止观看选项卡,则请求会变慢/停止。 - jesup
是的,我也得出了类似的结论。我已经在使用太多的Web Workers(用于媒体录制目的),所以我尝试使用其他对等请求每个帧,但如果选项卡处于非活动状态,则没有改进 :( - mido
传入的数据通道onmessage或websocket onmessage应该立即发生,因此如果您的选项卡处于非活动状态,您应该能够立即对其进行响应。如果不能,请尝试使用NSPR_LOG_MODULES=datachannel:5,timestamp NSPR_LOG_FILE=whatever的夜间版本。 - jesup

0

找到了一个可能的解决方案,至少对于Firefox来说,就是使用canvas并捕获它的流,并使用canvas.captureStream()进行传输。

// Find the canvas element to capture
var canvasElt = document.getElementsByTagName("canvas")[0];

// Get the stream
var stream = canvasElt.captureStream(25); // 25 FPS

// Do things to the stream
// E.g. Sent it to another computer using a RTCPeerConnection
//      pc is a RTCPeerConnection created elsewhere
pc.addStream(stream);

你好,我正在尝试同样的方法(从本地视频中捕获图像并将其转换为base64,然后将其分成块并通过数据通道发送)。但正如你所提到的,它很慢。这种新方法表现得更好吗?我希望这些图像在其他客户端上看起来像视频流。 - Cozdemir
@mido:你好,请问你能回答这个问题吗?https://stackoverflow.com/questions/62602079/windows-feed-a-webrtc-stream-to-a-virtual-driver - user2801184

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接