#嘿丝儿科技#一人单刷雨课堂需要多少工作量?快手工程师详解如何两周搞定( 二 )


编码模块
接下来是编解码模块 。 编解码是将经过前处理的音视频原始数据进行压缩 , 以达到网络传输的目的 。 由于网络资源的限制 , 原始的音视频数据量太大 , 不能直接在网络上进行传播 , 必须先经过压缩 。 压缩分为无损压缩和有损压缩 。 音视频数据通常采用有损压缩的方式 , 可以做到非常大的压缩比 。 视频编码算法常用的有H.264/H.265/VP8/VP9/AV1/AVS2等等 , 音频的压缩算法有AAC/Speex/Opus/G.711/G.729等 。 现在通常采用的视频压缩算法是H.264/H.265 , 而音频算法则大都采用Opus 。
压缩算法的细节非常繁杂 , 目前大多采用比较成熟的开源项目来实现 , 比如x264 , x265 , ffmpeg以及libopus 。 苹果设备也提供了内置的硬件视频编解码器videotoolbox可以支持H.264/H.265的实时编解码 , 而Android则有MediaCodec提供相同的能力 。 在桌面平台上 , Intel和NVIDIA的很多芯片提供了qsv和nvenc功能 , 用于实现桌面端的硬件视频编解码 。 有了编码器之后 , 还需要对编码参数进行正确的配置 , 以适合实时通信的场景 。 主要影响音视频通话体验的参数就是码率 , 在其他参数不变的条件下 , 码率越大音视频质量就越好 , 而使用的网络带宽也越大 。
这里为了简化实现 , 使用系统提供的编解码器实现 , 算1个人天 。
传输模块
经过编码之后的音视频数据已经小了很多 , 可以进行网络传输了 。 Internet网络传输协议分为TCP和UDP两种方式 。 TCP协议是可靠传输 , 保证数据的完整性和有序性 , 但是缺点是在公网传输时速度比较慢 , 延时比较大 。 而UDP协议是不可靠协议 , 数据只管发 , 不能保证一定能够到达对方 , 但是优点是发送速度快 , 延时低 。 因此在实时音视频通信里 , 都会优先使用UDP协议进行数据发送 。 UDP数据是以数据包为单位进行发送的 , 每次发送一个包 , 最大包大小不能超过64K字节 。 但是由于IP层的分片路由限制 , 通常一个UDP数据包的大小都会限制在一个MTU(MaxTransmissionUnit)以内 。 以太网的MTU为1500字节 , 因此每个UDP包的大小大多都会限制在1K字节左右 。 而编码后的视频数据相对于这个大小还是太大了 , 需要对视频数据进行进一步的分包才能进行发送 。
由于UDP协议的特性是不可靠传输 , 因此数据包达到的先后顺序也没有保证 。 为了让对方收到的音视频数据的先后顺序跟发送端一致 , 需要在接收端对UDP包进行排序 。 在视频会议上 , 通常会采用RTP协议对分包之后的数据包进行一层封装 , 每个RTP包都包含一个RTP头 , 里面为每个RTP包分配了一个序列号 。 这个序列号是有序递增的 , 因此接收端可以通过收到的RTP包的序列号对数据包进行排序 , 同时也可以知道哪些序号的数据包没有收到 , 从而向发送端请求重发 。
上面提到UDP在网络传输过程中可能会丢包 。 由于音视频编码后的数据需要完整接收才能进行正常解码 , 因此采用UDP协议传输的RTP包需要能够处理丢包恢复 。 丢包恢复的方式有两种 , 一种是FEC(前向纠错) , 一种是ARQ(自动重传) , 通常项目上这两个方法会同时采用 。
FEC是对一组RTP包进行冗余编码 , 产生出一些冗余包 , 冗余包包含了这一组RTP包的信息 , 在丢包的时候可以利用冗余包里的数据 , 恢复出这一组RTP包数据 。 常用的FEC算法包括RS、卷积码、喷泉码等 。 FEC的好处是不会引入额外的延时 , 冗余包和数据包一起发送给对端 , 对端通过接收到的数据包和冗余包尝试恢复 , 没有额外的交互时间 , 但由于网络丢包的随机性 , 并不是每一个FEC包都能够被利用 , 这样降低了整体的带宽利用率
ARQ则是精准的请求丢失的RTP包 , 让发送端重新发送 。 在RTP协议里 , 可以通过NACK来实现重传请求 , 携带上请求重传的RTP序列号 。 发送端接收到NACK请求后 , 会重新发送该序列号对应的RTP包到对端 。 NACK和重传包的传输引入了额外的延时 , 因此ARQ会导致音视频通信的延时增加 , 但是带宽利用率比较高 。


推荐阅读