【发布时间】:2021-12-08 16:25:56
【问题描述】:
我目前正在使用canvas.captureStream() 通过 WebRTC 发送画布流。这可以按预期工作,但我的画布是另一个视频的叠加层,因此具有透明像素。
我知道通常的 H26x 或 VPx 格式不支持透明度(另请参阅 Streaming video with transparent pixels using webrtc),因此我决定使用良好的旧色键(即 100% 绿色 == 透明)。
为了到达那里,我目前在启动时用透明绿色填充画布:
// already tried various composite ops here, none seem to work
// context.globalCompositeOperation = "destination-out";
context.fillStyle = "rgba(0,255,0,0)";
context.fillRect(0, 0, canvas.width, canvas.height);
这在客户端看起来是正确的(画布是透明的,无论我在上面绘制什么都不是),但是在通过 WebRTC 输出的结果流中,浏览器中透明的背景显然只是黑色,而不是绿色。我希望 alpha 值会被丢弃?
当我将 alpha 值更改为 0 以外的任何值(例如 1 或 128)时,结果不再透明,而是完全不透明的亮绿色,无论是在传出流(好)还是在浏览器中(不是好)。
我宁愿避免在 Javascript 中为隐藏画布上的每一帧手动执行 RGBA -> RGB 转换,这是我现在能想到的唯一选择。非常欢迎其他想法:-)
编辑:在 Ubuntu 20.04 上使用 Chrome 96 和 Firefox 94 进行了测试。 供参考,这里是合成操作的描述:https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Compositing/Example
【问题讨论】:
-
画布上会出现什么样的图画?根据用例的不同,会有非常不同的解决方案。例如,如果它“只是”一个绘图板,那么发送绘图命令而不是 MediaStream 可能会更好。如果它是网络摄像头提要上的“有趣的帽子”,那么“底部的视频+面具”解决方案可能会更好。但无论如何,是的,设置 ctx.fillStyle = "rgba(255,255,255,0)" 与将其设置为 "transparent" 或 "rgba(0,0,0,0)" 完全相同,alpha 是预乘的,任何透明像素都是透明黑色。
-
现在,它只是鼠标涂鸦,即绘图板。我也在考虑发送绘图命令,但还有其他非网络客户端只会发送视频,所以接收者也只需要视频(我希望这是有道理的)。在我在这里看到您的其他评论 (stackoverflow.com/questions/42146396/…) 后,我意识到我根本不需要进行像素转换,而是可以在第二个绿色画布上绘制画布图像并流式传输?
-
是的,虽然取决于内容,色度键可能无法很好地呈现(尤其是抗锯齿)。掩码意味着发送的数据更多,但质量更好。然而,无论采用何种解决方案,这些非 Web 客户端接收器将如何使用 MediaStream?他们能否正确地对数据进行后处理? FWIW,Chrome 确实支持透明录制。
-
非 Web 客户端在 Python 上运行 GStreamer WebRTC 组件,基本上只是混合/叠加几个视频流,因此让它们解析绘图命令将是相当可观的工作量。我想出了一个看起来相对有效的替代解决方案,请参阅发布的答案。
标签: javascript google-chrome firefox canvas webrtc