【问题标题】:Implementing a media device the browser can consume实现浏览器可以使用的媒体设备
【发布时间】:2018-05-31 18:52:50
【问题描述】:

我想创建一个供浏览器使用的媒体设备。也就是说,我想发布一个浏览器可以通过navigator.mediaDevices获取的视频流,通过WebRTC发送,打上<video>标签。

实际上,我正在做的是使用一个视频流(我从 C++ 中的一个循环中收集到它会吐出图像),读取它并分析它,我希望能够将流发送到浏览器.理想情况下,我希望能够从 Docker 容器中执行此操作。 C++ 进程也将作为节点绑定共存,但我不确定这是否相关。在这种情况下,我的意思是,如果通过绑定的 API 发送图像/视频流然后从 Node 发布是最简单的,那我没有问题。

任何人都可以提供有关如何在浏览器获取设备的任何地方注册人造设备的文档或阅读材料吗?我对司机什么的都不是很熟悉。

虽然我认为任何好的解决方案都会与其他系统相当交叉兼容,但我只需要它与 Ubuntu 16.04 和 Chrome 兼容。

【问题讨论】:

  • 这只是供您自己本地使用,即您可以安装驱动程序或依赖系统上的浏览器插件? (而不是通过互联网到任何 Chrome 浏览器?)
  • @Rup 严格来说,是的。我将通过 WebRTC 从同一台机器上的浏览器发送媒体设备,但我不认为这是相关的,只要浏览器可以正确使用它。但是,我真的宁愿避免以任何方式修改 Chrome 或 Linux。很高兴编写一个瘦驱动程序,这是我一直在努力研究的。我只是似乎找不到任何关于 API 或任何我可以使用的好的解释。
  • @Rup 我并不是要成为害虫,但是您对此有什么建议吗?我仍然空手而归
  • 对不起,不,我以前从未做过这样的事情。我的直觉是,如果使用插件可以做到这一点,那会更简单,但我怀疑不是。这是否必须通过 mediaDevices?对我来说,与普通的类似网络的视频流相比有什么好处并不明显。
  • 我不完全确定您所说的“类似网络的视频流”是什么意思,但如果您指的是托管视频,比如 mp4,我不知道不知道我是否可以将其流式传输到浏览器,我不知道我是否可以将其转换为 WebRTC 以后可以使用的格式,即使我可以,但如果它适用于我的用例,我会接受它。跨度>

标签: javascript c++ linux


【解决方案1】:

我最终得到的架构如下:

使用 FFmpeg(libavdevice/libavcodec/libavformat 等)的 C++ 输入到我使用 v4l2loopback 创建的设备中。然后 Chrome 可以检测到这个伪设备。 (只要你使用exclusive_caps=1选项如下图)

所以我要做的第一件事就是设置 v4l2loopback 设备。这是一个人造设备,可以像普通相机一样输出,但它也会像捕获设备或类似设备一样接受输入。

git clone https://github.com/umlaeute/v4l2loopback
cd v4l2loopback
git reset --hard b2b33ee31d521da5069cd0683b3c0982251517b6 # ensure v4l2loopback functionality changes don't affect this script
make
sudo insmod v4l2loopback.ko exclusive_caps=1 video_nr=$video_nr card_label="My_Fake_Camera"

浏览器会在navigator.mediaDevices.enumerateDevices()当且仅当您发布到该设备时才能看到该设备。要在通过 C++ 提供给它之前测试它是否正常工作,您可以使用ffmpeg -re -i test.avi -f v4l2 /dev/video$video_nr。出于我的需要,我使用的是 Puppeteer,因此测试起来相对容易,但请记住,长时间的浏览器会话会缓存设备并偶尔刷新它们,因此请确保 test.avi(或任何视频文件)很长(1 分钟以上),因此您可以尝试完全重置您的环境。我从来没有弄清楚缓存策略到底是什么,所以 Puppeteer 在这里非常有帮助,但我已经在使用它,所以我不必设置它。 YMMV。

现在(对我来说)最困难的部分是让 FFmpeg(libav-* 2.8 版)输出到这个设备。我不能/不会分享我所有的代码,但这里有一些部分和一些指导智慧:

设置:

  • 使用avformat_alloc_output_context2(&formatContext->pb, NULL, "v4l2", "/dev/video5") 创建一个AVFormatContext
  • 使用avcodec_find_encoder 设置AVCodec 并使用avformat_new_stream 创建AVStream
  • 您应该设置许多小标志,但我不会在此答案中逐一介绍。 This snippet as well as some others 包括很多这样的工作,但它们都面向写入磁盘而不是写入设备。您需要更改的最重要的事情是使用设备而不是文件创建AVFormatContext(参见第一步)。

对于每一帧:

  • 使用 OpenCV 的 cvtColor 将图像转换为正确的色彩空间(我的是 BGR,这是 OpenCV 的默认值)
  • 将 OpenCV 矩阵转换为 libav AVFrame(使用 sws_scale
  • 使用avcodec_encode_video2将AVFrame编码成一个AVPacket
  • 使用av_write_frame 将数据包写入AVFormatContext

只要您做对了这一切,它就应该将其馈送到设备中,并且您应该能够在浏览器(或检测到摄像头的任何地方)中使用您的视频馈送。


我要补充的一件事是专门针对 Docker 所必需的,即您必须确保在主机和容器之间共享 v4l2 设备,假设您正在使用容器外部的设备(我就是这样) .这意味着您将使用--device=/dev/video$video_nr 运行docker run 命令。

【讨论】:

  • 我要补充一点,我目前正在经历蓝移,在没有这种方法的情况下,图像比它自然出现的更蓝(只是直接从相机读取)。这可能是其中一个库的问题,但也可能只是省略实现的问题,或者至少在 C++ 中有解决方案。根据我们的需要,目前可以接受轻微的蓝移,所以我没有解决这个问题。
  • 小更新:蓝移不是我上面所说的一个因素。我从来没有修复过它,但更换到另一个相机确实修复了它,所以它一定是相机 API/我为我们使用的相机集成它的问题。
猜你喜欢
  • 2011-05-20
  • 2010-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-01
  • 2021-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多