当前位置:网站首页>webrtc中视频采集实现分析(二) 视频帧的分发
webrtc中视频采集实现分析(二) 视频帧的分发
2022-08-04 05:25:00 【mo4776】
文章目录
需求
在上一篇介绍了webrtc中的视频采集模块的接口。视频采集模块抛出视频数据后,对视频帧的处理需求一般包括如下几种:
- 视频帧送到编码模块进行编码
- 视频帧送到渲染模块进行本地回显
- 视频帧先进行预处理(比如添加水印,字幕),再送去回显或编码
- 视频帧会送到多个编码器,产生多路不同分辨率,码率的码流
相当于一个“源头”有多个“支流”,通过回调拿到的视频帧数据就是“源头”,如上的各种需求就是“支流”。视频帧数据要按需分发,满足各个“支流”的需要。那么在代码中的体现就是一个source,多个sink。
分发框架涉及到类
webrtc中有一个对视频帧的分发框架,可以直接复用,包括videoSourceInterface,videoSinkInterface,VideoBroadcaster
videoSourceInterface
作为source的基类,指“源头”
- 主要接口是
AddOrUpdateSink()和RemoveSink(),videoSourceInterface可以添加多个sink AddOrUpdateSink接口的第二个参数是VideoSinkWants结构体,下面是它的定义
struct VideoSinkWants {
VideoSinkWants();
VideoSinkWants(const VideoSinkWants&);
~VideoSinkWants();
// Tells the source whether the sink wants frames with rotation applied.
// By default, any rotation must be applied by the sink.
bool rotation_applied = false;
// Tells the source that the sink only wants black frames.
bool black_frames = false;
// Tells the source the maximum number of pixels the sink wants.
int max_pixel_count = std::numeric_limits<int>::max();
// Tells the source the desired number of pixels the sinks wants. This will
// typically be used when stepping the resolution up again when conditions
// have improved after an earlier downgrade. The source should select the
// closest resolution to this pixel count, but if max_pixel_count is set, it
// still sets the absolute upper bound.
absl::optional<int> target_pixel_count;
// Tells the source the maximum framerate the sink wants.
int max_framerate_fps = std::numeric_limits<int>::max();
// Tells the source that the sink wants width and height of the video frames
// to be divisible by |resolution_alignment|.
// For example: With I420, this value would be a multiple of 2.
// Note that this field is unrelated to any horizontal or vertical stride
// requirements the encoder has on the incoming video frame buffers.
int resolution_alignment = 1;
};
主要就是描述sink期望的分辨率,帧率等,上面的注释也写的很明白了。
videoSinkInterface
作为sink的基类
主要接口是OnFrame()和OnDiscardeFrame()
这两个类就代表着source和sink,一个source中可以添加多个sink,source通过调用sink中的OnFrame方法,将视频帧数据传给sink
VideoBroadcaster 视频帧分发类
- VideoBroadcaster类,看名字就知道是视频帧分发类。上面的类图可以看到,VideoSourceBase既是一个source也是一个sink。
VideoBroadcaster可以放入对个sink,但它会对所有的sink集合的want做个合并,取的帧率帧率值是sink want中的最小值,分辨率的值也是sink want中的最小值但是source提供的视频帧不满足sink时就需要对视频帧数据做适配了,那么
VideoAdpater就是这样的作用了
VideoAdpater
VideoAdpater相当于一个filter,对source中的视频帧进行过滤,来满足sink的要求
VideoAdpater可以实现对帧率的过滤和对分辨率的缩放
基本框架
通过上面的这几个类的关系,就拼出了一个视频帧分发的框架

videocaputre代表视频采集模块,它到代表了总的数据“源头”,通过回调将视频帧数据给VideoBroadcaster,VideoBroadcaster再将视频帧分发到各个sink。
前一篇文章中 VideoCaptureModule有个回调注册接口void RegisterCaptureDataCallback(rtc::VideoSinkInterface<VideoFrame>* dataCallback),可以将VideoBroadcaster作为sink注册。
需要注意的是,VideoBoradcaster并没包含VideoAdpater类,它没有适配功能,只是单纯的分发。如果要对视频帧数据进行适配就需要在VideoBoradcaster得前面或后面加上VideoAdpater。
变化
webrtc中的VideoBoradcaster的用途是有局限的,它并不能实现不同帧率,不同分辨率的分发(上面提到它会对所有的sink wants做合并,取sink wants中的帧率,分辨率的最小值)。它适用于对帧的用途的分发,比如有的被送去编码,有的被送去本地回显,都是同一种分辨率和帧率。
所以上面的这个组合图,是并不能满足产生多路不同分辨率,帧率的码流场景。
考虑这样一个需求:
- 能产生三路码流,它们有不同的分辨率,帧率
- 能本地回显
所以需要像下面这种方式来进行组合了
videocatpure采集的视频是30fps,720P。需要产生三路码流(有三个编码器对象)和本地回显,VideoAapter不能放在VideoBroadcaster前面,因为VideoBroadcaster只能输出同样的帧率和分辨率。需要在video encoder前面放一个VideoAapter,满足帧率,分辨率的要求。
VideoAapter在满足帧率时,会进行丢帧处理,所以这三个VideoAapter+Video encoder应该是分别在一个线程中。
webrtc中的例子
在例子peer_conection_client的实现中,是通过TestVideoCapturer类集成了VideoAdapter和VideoBroadcaster,可以参考下如何实现将它们连接起来的。但是在浏览器的实现中应该不通过TestVideoCapturer实现的,因为它的实现是满足不了需求多路不同分辨率,帧率的码流的。
边栏推荐
- OpenCV获取和设置图像的平均亮度
- 败给“MySQL”的第60天,我重振旗鼓,四面拿下蚂蚁金服offer
- DP4398:国产兼容替代CS4398立体声24位/192kHz音频解码芯片
- What is the salary of a software testing student?
- The symbol table
- 在被面试官说了无数次后,终于潜下心来整理了一下JVM的类加载器
- 利用Jenkins实现Unity自动化构建
- 嵌入式系统驱动初级【4】——字符设备驱动基础下_并发控制
- Do you think border-radius is just rounded corners?【Various angles】
- PHP解决字符乱码问题(多种编码转换)
猜你喜欢

关于C#的反射,你真的运用自如嘛?

day13--postman interface test

OpenSSF 安全计划:SBOM 将驱动软件供应链安全

在被面试官说了无数次后,终于潜下心来整理了一下JVM的类加载器

The cost of automated testing is high and the effect is poor, so what is the significance of automated testing?

嵌入式系统驱动初级【4】——字符设备驱动基础下_并发控制

PHP实现异步执行程序

What is the salary of a software testing student?

一个对象引用的思考

8.03 Day34---BaseMapper query statement usage
随机推荐
Resolved error: npm WARN config global `--global`, `--local` are deprecated
7.15 Day21---MySQL----索引
Camera2 闪光灯梳理
The string class introduction
EventBus源码分析
如何将 DevSecOps 引入企业?
4.1 声明式事务之JdbcTemplate
MySQL日志篇,MySQL日志之binlog日志,binlog日志详解
TensorRT例程解读之语义分割demo
力扣:96.不同的二叉搜索树
TensorRTx-YOLOv5工程解读(一)
FPGA学习笔记——知识点总结
7.13 Day20----MYSQL
Tactile intelligent sharing - SSD20X realizes upgrade display progress bar
MySQL日期函数
Canal mysql data synchronization
Oracle备份脚本
利用Jenkins实现Unity自动化构建
ORACLE LINUX 6.5 安装重启后Kernel panic - not syncing : Fatal exception
MySQL database (basic)