实现浏览器可以使用的媒体设备
Implementing a media device the browser can consume
我想创建一个供浏览器使用的媒体设备。也就是说,我想发布一个浏览器可以通过navigator.mediaDevices
获取的视频流,通过WebRTC发送,放入<video>
标签。
实际上,我正在做的是消耗视频流(我从C++中吐出图像的循环中收集到它(,读取它并分析它,我希望能够将流发送到浏览器。理想情况下,我希望能够从 Docker 容器执行此操作。C++过程也将作为 Node 绑定共存,但我不确定这是否相关。在这种情况下,我要说的是,如果通过绑定的 API 发送图像/视频流然后从 Node 发布是最容易的,我对此没有问题。
任何人都可以提供有关如何注册人造设备的文档或阅读材料,无论浏览器从何处获取设备?我对司机或任何东西都不是很熟悉。
虽然我认为任何好的解决方案都会与其他系统相当交叉兼容,但我只需要它与 Ubuntu 16.04 和 Chrome 兼容。
我最终得到的架构如下:
使用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在这里非常有用,但我已经在使用它,所以我不必设置它。扬子晚报.
现在(对我来说(困难的部分是让 FFmpeg(libav-* 版本 2.8(输出到这个设备。我不能/不会分享我的所有代码,但这里有一些部分和一些指导智慧:
建立:
- 使用
avformat_alloc_output_context2(&formatContext->pb, NULL, "v4l2", "/dev/video5")
创建AVFormatContext
- 使用
avcodec_find_encoder
设置AVCodec
并使用avformat_new_stream
创建AVStream
- 您应该设置一堆小标志,但我不会在这个答案中介绍所有这些标志。这个片段以及其他一些片段包括很多这样的工作,但它们都是针对写入磁盘而不是设备。您需要更改的最大内容是使用设备而不是文件创建
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
命令。
- 如何将不同的可执行文件合并到一个窗口框架中进行编码?像浏览器一样
- 应用程序无法找到铬边缘浏览器
- 如何从WebAssembly模块检测浏览器信息?
- 将音频从浏览器流式传输到WebRTC本机C++应用程序
- 使用IMFSourceReader(Microsoft媒体基金会)进行音频流传输
- c++ 网络浏览器块 url
- 谷歌浏览器在访问网站时发送第二个 0 长度的请求?
- 媒体基金会:WavSink以比实时消耗率更快的速度处理音频-是否可以实时限制后台处理
- DwmGetWindowAttribute 在全屏模式下无法获得媒体播放器的正确矩形大小
- 媒体基础 多个视频播放导致内存泄漏和崩溃
- 我的web应用程序的用户需要在浏览器上手动启用本机客户端吗
- 媒体基础将音频流添加到视频文件
- C++检查网络浏览器是否关闭
- 使用 Cmake 闪烁浏览器引擎示例?
- 直接显示通用媒体解码器
- 用于 c++ 媒体流的 N-API 连续回调
- 媒体基金会可以允许多个客户端同时访问单个网络摄像头设备吗?
- NV12 至 RGB32,带Microsoft媒体基础
- 实现浏览器可以使用的媒体设备
- C++/OpenCV流媒体摄像机视频/图像(MJPEG)从套接字进入浏览器(Windows 8.1)