主流业务场景协议与痛点
- 短视频:http,海量码流格式、容器格式需要支持
- 秀场类直播:rtmp、http-flv、hls,延时、卡顿
- 摄像头监控:rtsp、延时、丢帧
协议 | 传输方式 | 封装格式 | 延时 | 数据流 | H5直播 | 应用场景 |
---|---|---|---|---|---|---|
HLS | http | m3u8/ts | 10s以上 | ts切片 | 支持 | 直播拉流 |
RTMP | tcp | flv | 2s左右 | 连续流 | 不支持 | 采集推流 |
HTTP-FLV | http | flv | 2s左右 | 连续流 | 支持 | 直播拉流 |
系统自带播放器的局限性
- 支持的协议有限
- 支持的码流格式有限
- 支持的容器格式有限
- 不支持流式播放
- 关键模块封装的严实,无法自定义和调试,排查问题困难
播放器核心架构
- FFmpeg负责解协议解封装得到AVPacket根据类型分包到音视频压缩数据队列
- 音视频解码器解码出AVFrame,iOS硬解码出来直接是CVPixelBufferRef格式,放入音视频渲染队列
- 音频帧使用AudioUnit渲染,根据系统回调喂数据,视频帧根据同步帧率控制,进行渲染,渲染引擎同时支持Metal、openGLES
FFMpeg裁剪包
- FFmpeg负责解协议、解容器同时支持协议容器格式任意裁剪
- 基础包用于常规业务
- 可以根据特定业务类型自定义裁剪包
- 全量包用特殊业务
解协议、解封装、解码
- 建立链接获取字节流
- 创建解析器得到媒体流信息包括音视频格式、时长、码率、帧率等信息
- 创建解复用器循环读取压缩数据包放入压缩数据队列
- 根据码流信息创建解码器得到yuv和pcm放入带渲染队列
Buffer队列
- 抵抗网络抖动
降低卡顿率,没有Buffer队列的数据流:IO->Parser->Demuxer->Decoder串行执行,当网络抖动的时候会出现CDN缓存的较多的数据(现在主流设计只会缓存几帧),导致TCP发送队列爆满而产生被动丢帧,导致网络恢复的时候下发到客户端的数据不完整而产生花屏 - 抵抗解码抖动
解码某些复杂码流的时候,某些帧可能耗时比较久,如果解码器卡住,永阳IO也会阻塞 - Buffer队列设计引入的问题
Buffer越大,内对占用越高、延时越高
因此需要根据不同业务场景配置相应的buffer策略
- 点播
缓存大小可以适当的大一些,但也要控制好内存,移动网络下长度控制在15秒以内,wifi下可以控制在30秒内 - 直播
场景 | 策略模式 | 详情 |
---|---|---|
秀场 | 流畅模式 | 正常缓存播放 |
语音房 | 加速模式 | 大于delaytime,倍速播放 |
IOT | 低延时模式 | 大于delaytime,丢帧 |
音视频渲染
- 视频渲染挑战
iOS支持openGLES,但是2018年的WWDC上,苹果公司发布了正式版的iOS12,同时宣布弃用openGLES并且在后续的iOS版本中会逐步替换底层库的相关代码使之向metal演变
1、Metal支持的操作系统:iOS、macOS X
2、Metal的硬件要求:A7处理器,ARM64以上,就是iphone5s以上的机型,不支持x86
3、Metal支持的系统版本:Metal:iOS8,MetalKit:iOS9
因此需要支持模拟器和低版本的系统,需要实现两套方案,需要设计openGLES与Metal的适配器以供播放器控制自由切换
- 音频渲染挑战
iOS系统支持流式播放的音频框架有opengAL、audioQueue、audioUnit
openAL所有实例共享一个上下文,不符合播放器多实例的特性,并且一个实例发生错误,所有实例均不能在使用;openAL、audioQueue都是封装的audioUnit,audioUnit更接近硬件,延迟最低性能最佳
1、设置app是否与其他应用混音
2、手机静音app是否正常播放出声音
3、电话或其他应用抢占音频设备事件处理
4、动态切换音频路由
5、是否支持录音,录音同时是否支持播放
音频中断事件处理复杂,当中断发生时如果音频权限同时被修改会收不到中断恢复消息,从而导致音频播放卡住,因此需要程序回到前台统一处理
播放器状态机
播放器通用接口
- 创建/销毁播放器(支持多实例)
- 参数动态配置(渲染模式、解码方式等)
- 发送指令 (播放、暂定、seek等)
- 原始码流回调(支持外部渲染)
- 状态消息回调(缓冲、播放完成、错误等)
网友评论