当前位置:网站首页>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
实现的,因为它的实现是满足不了需求多路不同分辨率,帧率的码流的。
边栏推荐
猜你喜欢
Can‘t connect to MySQL server on ‘localhost3306‘ (10061) 简洁明了的解决方法
The idea setting recognizes the .sql file type and other file types
Performance testing with Loadrunner
canal实现mysql数据同步
符号表
Dynamic programming of the division of numbers
在被面试官说了无数次后,终于潜下心来整理了一下JVM的类加载器
[Cocos 3.5.2]开启模型合批
7.16 Day22---MYSQL (Dao mode encapsulates JDBC)
EntityComponentSystemSamples学习笔记
随机推荐
力扣:63. 不同路径 II
The symbol table
FPGA学习笔记——知识点总结
[Evaluation model] Topsis method (pros and cons distance method)
MySQL数据库(基础)
力扣:343. 整数拆分
MySQL数据库面试题总结(2022最新版)
[Cocos 3.5.2]开启模型合批
8款最佳实践,保护你的 IaC 安全!
php实现telnet访问端口
乱码解决方案
符号表
MySQL date functions
7.16 Day22---MYSQL(Dao模式封装JDBC)
DP4398:国产兼容替代CS4398立体声24位/192kHz音频解码芯片
How to view sql execution plan offline collection
TensorRTx-YOLOv5工程解读(一)
Cannot read properties of null (reading ‘insertBefore‘)
8.03 Day34---BaseMapper查询语句用法
4.3 Annotation-based declarative transactions and XML-based declarative transactions