四个适配器,一边一个
项目侧已有的接口是固定的:数据源有采集回调那一族,编码器有输入、释放和编码包回调。WebRTC 侧要的也是固定的:轨道源、音频源接口、视频音频编码器接口。两边对不上,适配器各接一个:
视频源与音频源,桥成它的轨道源与音频源接口;视频编码器与音频编码器,桥成它的编码器接口。再往上,一个统一入口把信令、两条数据流和渲染整合起来,WebRTC 内部跑的就全是项目自己的源和编解码器。

视频源:一次采集,两边各取一份
视频源适配器内部挂了一个广播器:收到的每一帧同时发给所有消费者——本地预览窗口一份,编码器一份。数据只采一次,预览和编码各取一份,CPU 和 GPU 都省。
资源是跟着消费者走的:第一个消费者注册时,才打开底层采集源、起本地预览窗口;最后一个走了,自动关掉。挂着的图像处理是现成的那套——本地预览与送编码前的画面走同一趟渲染,裁剪缩放、水印、滤镜都在里头。
输出形态按编码器吃什么定。能直接吃 GPU 纹理的硬编,比如 Apple 的 VideoToolbox,纹理直接给,不往 CPU 落(引用计数加一道,防着纹理提前释放);要 CPU 数据的,用计算着色器把 RGBA 转成要的 YUV 格式,就是普通播放里渲染出图用的那一路。Windows 单独说:硬编暂时没有直接吃 D3D11 纹理的输入口,所以先落到 CPU 的 NV12,再按显卡交给对应的硬编——软编兜底时则转成 yuv420p。落到哪一种,由源侧一个输出形态的开关决定,起编码器之前设好,链路就按它走。这与普通播放那边硬编的结论是同一条:编码器是硬的,纹理直喂那条路还没接上。

音频源:归一与切片
音频源适配器一身三职:WebRTC 的音频源接口、播放器侧的采集回调、加上那个归一与切片的重整形器。归一规则与音频前处理那一篇相同——44100 改写成 48000、转 S16、声道收到二,然后切成 10ms 一段,按位深、采样率、声道数一帧一帧喂给 WebRTC。消费者的开关逻辑与视频源一样:有人才开,没人就关。
视频编码器:进和出各转一道
编码器适配器实现 WebRTC 的编码器接口,里头包着项目自己的编码器,覆盖各平台 H264、H265 的硬编。建的时候按平台与硬编配置从注册表取默认名——Apple 取 VideoToolbox 的 H264,别的平台各有各的默认;起编码器时它会把初始码率一并给下来,设进底层,之后的调整都走码率回调那条路。取不到默认名就报错,不做运行期降级,候选链那套降级机制挂在录制推流那条腿上,这条路没接。音频编码器那一侧与视频同构:声明的格式列表与解码侧一致,协商到 AAC 就用项目自己的编码器。
进来的帧先转一道:WebRTC 的帧由一个双模式缓冲承载,CPU 模式是 YUV 帧,GPU 模式带着纹理;原生帧直接进硬编吃纹理那条路。出去再封一道:编码包回调里把项目的包封成它的编码帧——RTP 时间戳从进帧时记下的对应关系里取,采集时间用包自带的 pts,帧类型按 NAL 单元判是不是关键帧,头里标上编码类型。Apple 硬编吐的是长度头装法,这里判过一次之后统一转成起始码,后面的 RTP 打包就顺了。
码率是 WebRTC 说了算:它按网络状况算出目标码率,回调里取出来设到底层编码器。编码器只管照办,自己不另做一套码控。关键帧也是它要:网络一抖、或者有新端点加入,它会发来「下一帧要是关键帧」的请求,适配器把这个请求原样转给编码器——画面能在丢包之后很快恢复,靠的就是这一下。

顶层把两边拼起来
统一入口实现播放器接口,同时是命令执行体和事件观察者——上一章框架里那几个角色它都在当,只是里头的源和渲染换成了 WebRTC 这一套:信令与数据流、本地画面、远端画面、远端声音四样整合在一起。角色分两种:发起方主动 CreateOffer,适合拿 HTTP 接口换 SDP 的推流;应答方被动等 offer 再作答,适合有长连接通道的通话。选角色就一个调用,它据此调整本地与远端描述的设置顺序:发起方先出 offer、设本地,收到对方 answer 再设远端;应答方反过来,先把收到的 offer 设成远端,再作答、设本地——顺序乱了,协商就死在一半。
渲染全是复用:本地预览、远端画面、远端音频,取的都是项目原有的那几个渲染器,底下是同一套 Vulkan 图像处理与硬件渲染。用法上设好数据源、调 open 就起来了;自带的示例里,音频取 Windows 声卡设备,视频取屏幕采集设备,地址用带推流标记的 WebRTC 接口,十几行就把一次推流跑通。
这一章到这儿齐了:库怎么接进工程、录音的回声噪音、拉流侧自己的解码与渲染、推流侧自己的采集与硬编,各有各的一篇;WebRTC 只负责网络这一段,弱网里把数据送过去。
引擎 avox 在 GitHub 开源:github.com/xxxzhou/avox,四个适配器与统一入口都在里面。
音视频开发 WebRTC 推流 硬件编码 采集 C++ 实时通信