webrtc是一个比较成熟的实时音视频处理开源项目,一上来老大就扔给我一本webrtc native实践,虽然狠下心“翻”完了一遍,但是还是云里雾里的,在经过几个月的摸索之后,我大概知道原因了,归根到底,是基础不在一个层次,理解不了的,所以我决定,尝试写一个接近我这种零基础入门实时音视频的记录系列,希望能帮到一些同学
基础概念的理解
实时音视频是一个很长的流程,从采集-编码-传输-接收-解码-渲染,每一个步骤都是很大的模块,所以我们一个一个来,我们先从采集相关的设计开始,我们先看一些概念,否则直接看代码会有点懵
stream(流):包含音频轨和视频轨的编码流
track(轨道):音频轨或者视频轨
音视频同异点-我的理解
先说几个点
- 音频和视频还是很多地方不一样的
- 音频采集了,自己不不要同时听到自己,一般只需要传输给对方;一般只有一个采集的地方;即使有多个采集的地方,对方希望听到是合流之后的一个声音;
- 视频采集了,一般需要同时在己方和对方都渲染显示出来;可能要多个采集源;一般希望每个视频源独立展示(甚至是不同的设备展示)
- 音频和视频有很多地方是一致的
- 是同级的概念;整体的处理流程几乎一致
- 音频和视频输入和输出的过程不一样
整体感觉是视频的逻辑要比音频复杂一些,所以下面我主要也是围绕视频展开,音频也会顺便说下
视频代码设计
其实这个地方很难真正从零开始,我这里也是从中间某个点开始说(对着代码说自己的理解);结合上面的同异点,我们来看下webrtc里面的代码设计
source和sink
这是我觉得第一个坑的设计,但你理解了之后,觉得这样设计也没有问题
联系实际场景,摄像头采集到图像之后,保存视频,成为视频源,编码和本地渲染需要消费图像做处理,类似于生产和消费的概念
对于消费者,也就是sink来说,如果我想要增加一个消费者,我继承sink接口,塞到保存视频源的实例里面去,让实例不断给我塞数据给我消费即可(onFrame),所以sink的接口定义比较好理解;
source的接口定义里面只有对sink的操作,这是我觉得一开始不好理解的地方,source并没有存储视频图像(为什么叫source呢?);我现在的理解是,相对于sink,这样的接口就可以理解为source(摄像头采集图像之后,调用source的某个接口,这这个接口里面,对图像数据进行分发给sink,对于sink来说,这个实例就可以理解为source);
videoBroadcaster
broadcaster做的就是我们上面那段话想做的事情
source的接口太简单了,下面是videoSourceBase的函数定义,还增加了一个sinks的成员来保存所有的sink成员;
而broadcaster同时继承了sink和source,这就是我们想做的事情:初始化一个broadcaster实例,增加一个消费者sink的时候,把sink通过broadcaster的source接口存入sinks即可;当采集到图像的时候,把图像按照既定的逻辑调用所有sink的接口即可;
webrtc里面同时是sink又是source的实例还有很多,例如
这是第一个实际概念到代码设计的实践,可以看到,简单的物理概念想真正用代码设计构架起来,还是需要很多抽象设计和构架思考的
source、track、stream
上面说完了整体一个大概念的图像采集之后,采集分发的小流程,这些图像数据source要变成track最后要形成 stream,我们看下这里的设计,在这些之前,有些更细节的概念也要考虑到,例如音视频发生了变化需要通知观察者
所以首先定义了观察者接口和通知者接口,都是很纯粹的接口定义
而通知者的继承关系则很长,通知接口有三个继承者MediaSourceInterface,MediaStreamTrackInterface,MediaStreamInterface,基本source、track、stream都是通知者
MediaSourceInterface
定义了媒体源的基本状态,媒体大类有两个,音频和视频,所以有两个继承者VideoTrackSourceInterface,AudioSourceInterface,上面也说到过,音视频细节上有些差异,从这里的接口设计可以看到一些
AudioSourceInterface
AudioSourceInterface的接口,例如音量这些,都是音频独有的
VideoTrackSourceInterface
因为之前已经定义了VideoSourceInterface,所以这里直接到了videoTrackSource的定义
从audio和video两个继承来看,这里的分化挺明显的
MediaStreamTrackInterface
track的定义和继承如下,定义了trackState和必要接口;同时可以看到有音视频track两个子接口
videoTrack
audioTrack和VideoTrack有一个不一样的地方是,audioTrack只是组合了audioSource,videoTrack还继承了videoSource,我理解这是因为视频的来源和分发比音频复杂,因为所有的音频可能最后会汇聚成一个,是多个视频源可能需要分发和处理到不同的地方;
MediaStreamInterface
最后继承Notifier的是MediaStreamInterface,可以看到,stream是videoTrack和audioTrack的组合
好了,今天就先写到这里,后面应该会持续更新
p