音视频学习 -- 新 codec 适配和兼容

本文主要描述一种新的 codec 在 VOIP 整个流程中添加的基本流程,以及所设计到的各种模块的适配:
日常工作中有涉及到新的 codec 添加的需求和规划内容,可以参考本文添加;想要学习音视频整个流程,也可以借鉴参考。
0 前言
所涉及的模块和内容基本如下:

1. sip 模块适配
sip 模块涉及到 codec 相关信息的协商和参数解析内容
1.1 构建 sdp
Sip 中针对 IP 直播方式或者 sip 账号方式,分别增加对应的 codecName、codecPayload、videoMaxBR 等参数信息。

同时在 videocodec list 中增加 CodecName、Ext 数据信息。这些最终会写入 sip 协商的 SDP 中,完成视频 codec 的备选。


SipCall 模块获取本地 codec 列表中增加 codec 过滤项

sipVideoManager 中在过去 localMaxBR 值时,增加对应的选项


1.2 解析 sdp
解析时,就需要拿到 SIP 包中相关数据进行保存和数据解析,有对应的库和类型可以参考构建 sip 的模块。
2 SipPhone Java 端适配
SipPhone 端涉及到 codec 参数具体设置到 MediaStack 部分的接口修改

2.1 编码器设置

2.2 解码器设置

3 WebRTC 框架适配
WebRTC 部分涉及到 codec 参数设置;codec 创建、初始化、软硬件编解码选择、对应参数设置等,以及音视频数据从网络端获取、解析、缓存、送解码、显示等内容。相关框架图:

3.1 webRTC 参数设置

(1)get_codec_type,获取设置为 kVideoCodecH263 类型

(2)get_decoder_impl 和 get_encoder_impl,根据类型区分不同的 codec 类型,创建对应的 decoder 和 encoder 实现对象。(会根据硬解软解、硬编软编来区分不同的构建对象,采用工厂模式进行构建)


(3)config_decoder_params 和 config_encoder_params,分别配置解码器和编码器参数,设置 callback 函数


3.2 codec 构建
该部分是 codec 编解码器的构建核心部分,主要涉及到一些参数的设置,初始化,编解码器创建的初始化,context 设置等。

3.2.1 软解软编
软解软编,主要调用 FFMPEG 接口进行软解,比如解码时调用 FFMPEG 中的 avcodec_decode_video2 接口进行软解、通过 OnSwDecodeCompleted 接口反馈解码后的数据;

软编时调用 avcode_find_encoder 查找编码器、通过 avcodec_alloc_context3 接口分配上下文 context,通过 avcodec_get_context_default3 查找 codec 信息,调用 avcodec_open2 打开 codec,通过 avcodec_encode_video2 进行编码。

3.2.2 硬解硬编
硬编、硬解相关的功能一般看具体厂商的支持程度了,硬件厂商一般支持 H263、H264、H265、VP8、AV1,部分支持 VP9、JMPEG 等其他的编解码格式。
目前采用的厂商对于 H263+格式不支持硬编,因此参考 H264 适配其他编解码器,具体代码如下:需要优先初始化编码器、构建硬件厂商需要的 context 数据、设置对应的参数信息、比如帧率、码率、分辨率、profile、level、YUV buffer 等参数信息,以及解码后存放数据的指针地址。

硬解的代码如下:

3.3 rtp_rtcp 解析
RTP rtcp 收包、解包框架

3.3.1 receiveVideo
收到 RTP 包后,进行 H263 解析,并最后通过 ReceiveH263CodecCommon 函数封装成 RTP 数据包送到 JitterBuffer 中进行数据包组装


3.3.2 SendVideo
发送数据是把一帧图像按照 RTP 格式进行封装为 RTP 数据包,并将其发送到网络中


3.3.3 rtp 解析
rtp 解析主要包括 RTP 包解析和封装,包括 RTP 包头的数据解析、rtp type 判断等,该部分就不再列数代码了。
4 FFMPEG 框架适配
FFMPEG 端涉及到软件编解码部分流程,包括 FFMPEG 编译、对应 codec 选项开启、FFMPEG so 库更新到 WebRTC 中,以及对应 codec 是否支持、以及 codec 具体接口介绍。
4.1 FFMPEG 编译
4.1.1 正常是执行./configure,我们是 Android 平台,因此选择./configure_android.sh 即可

4.2 codec 选项开启
将对应的 codec 进行开启,通过--enable 命令开启,该部分和 FFMPEG 官方中的描述一致,不清楚的可以自行百度一波。

在 config.h 中将 H263decoder 和 encoder 都开启:


否则,H263 编码器和解码器在 FFMPEG 中无法使能。
4.3 FFMPEG so 库更新
4.3.1 FFMPEG 编译
之后执行 make install,会根据配置中 enable 相关项进行特定模块的编译,从而打开对应的 codec 编解码
因为 FFMPEG 是按照模块配置进行编译的,因此各个模块必须完全配置正确才可以编译到最终的库文件中。所以一些 codec 相关配置要同步打开,具体路径和文件如下几个截图

在 allcodecs.c 中将 H263 的编码和解码器进行注册

REGISTER_ENCODER(X,x)和 REGISTER_DECODER(X, x)的定义描述如下:

至此 FFMPEG 中相关 codec 配置完全打开,编译出来的中间进行替换即可
4.3.2 WebRTC 编译
WebRTC 中 jni\webrtc\sources\webrtc\jni 编译脚本如下:

从android.mk中可以看出,WebRTC 中采用的是 third_party_ex 中 FFMPEG 相关部分,因此将第一部分中编译完成的 libavcodec.a 等相关文件拷贝到 WebRTC 中,FFMPEG 所需库文件如下 \webrtc\sources\webrtc\jni\third_party_ex\libs:

把编译完成的 FFMPEG 中间文件全部替换一下即可
4.4 codec 介绍
本节简单介绍一下如何确认 FFMPEG 中是否支持需要的 codec,以 H263 为例
在 libavcodec 中查找相关 h263 codec 信息即可看到是否支持


5 硬件编解码适配
主要介绍硬件编解码对应如何适配,相关接口介绍,如何查找对应厂商手册,可以参考官网,然后按照对应的 API 进行封装即可,在此不再类述。
以上
欢迎点赞、评论、关注、转发;随时探讨,持续输出。

版权声明: 本文为 InfoQ 作者【Fenngton】的原创文章。
原文链接:【http://xie.infoq.cn/article/ac4f5d15711f32b9b43b05eba】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论