音频缺失录制分析
- 2020 年 1 月 20 日
- 笔记
实验框架:
RTMP Reader和Muxing各自包含音视频的AVCodecContext,共四个AVCodecContext
背景:
用户实际推流过程中,存在推流无音频数据的异常场景,导致录制RTMP Reader无法正确初始化音频的AVCodecContext,进而影响录制Muxing音频AVCodecContext初始化,最终导致录制文件出现静音等问题。
正常的音频推流过程是:AAC Sequence header | AAC data | AAC data | …… | AAC data
场景1:视频包正常推送,音频包则只推送AAC Sequence header,对应推流端代码是
1.正常初始化推流端RTMP Reader的音视频AVCodecContext
2.正常初始化推流端Muxing的音视频AVCodecContext
3.调用avformat_write_header
4. RTMP Reader读取音频视频包,Muxing写视频包,丢弃音频包
抓包如下:
红框中包含on mata data和视频的sps/pps以及音频的AAC Sequence header
结果:
录制RTMP Reader堵塞于avformat_find_stream_info直至超时返回,此时RTMP Reader的音视频AVCodecContext均已存在,但是音频AVCodecContext并未正确初始化,音频AVCodecContext如下:
红框的重要信息中只有bit_rate存在了,其他全未被初始化,用该音频AVCodecContext初始化Muxing的音频AVCodecContext时,ffmpeg会报错:
此时若忽略音频的AVCodecContext,可以正常录制静音文件,这样做存在的问题是若后续推送了正常的音频数据,也会被录制端忽略。
场景2:视频包正常推送,音频包完全不推送,对应推流端代码是
1.正常初始化推流端RTMP Reader的音视频AVCodecContext
2.正常初始化推流端Muxing的视频AVCodecContext,初始化音频AVCodecContext为0,不打开音频stream
3.调用avformat_write_header
4. RTMP Reader读取音频视频包,Muxing写视频包,丢弃音频包
抓包如下:
红框看到只有on mata data和video的sps/pps,没有audio的AAC Sequence header
结果:
录制RTMP Reader堵塞于avformat_find_stream_info直至超时返回,此时RTMP Reader的视频AVCodecContext已生成并初始化,而音频AVCodecContext指针则为0,忽略音频录制则静音录制。缺点同场景1。
场景3:视频包正常推送,音频包以及aac sequence header均延迟推送,该场景需要修改rtmp server的代码实现,对应的代码实现是
1.推流端初始化时推送aac sequence header,音频数据则延迟推送
2.rtmp server接收到aac sequence header先进行保存,等到第一个音频数据包达到再一起推送给录制模块,实现均延迟的效果
录制中途,日志有(ffmpeg发现了上行音频stream):
结论同场景2.
场景4:视频包正常推送,音频包只发送数据,不发送aac sequence header,代码实现:
1.rtmp server接收到aac sequence header直接丢弃,只发送后续音频数据包
该场景实际是会影响音频AVCodecContext的extradata的初始化,该场景中,录制代码对录制hls和非hls有不同的做法,录制hls时,放弃录制音频,其他格式则依旧使用无extradata的AVCodecContext录制。
本实验也对该场景做了详细实验:
1.录制flv/mp4时,无extradata也可以正常录制音频数据,播放正常;
2.录制hls时,若强制使用无extradata的AVCodecContext进行录制,则会core掉(这也是录制代码当时要区分hls与非hls录制逻辑的原因);
录制优化:
当前版本,录制初始化设置获取音视频AVCodecContext超时时间为90秒,并有重试逻辑,获取3次不成功就会减少超时时间,最终还不成功则忽略音频AVCodecContext,直接录制静音视频。实验过程中发现,以上3种场景,只要推流端之后能正确推音频数据上来,录制中使用avformat_open_input得到的AVFormatContext中的音频AVCodecContext都会被正确初始化。意味着,如果录制途中再去获取音频的AVCodecContext是可以获取到的,这刚好适用于录制hls的场景,因为录制每次切ts分片的时候都会重新调用setup muxing。
优化效果:
假定,m3u8里有两个ts分片,1.ts和2.ts,1.ts不含音频数据,2.ts含有音频数据(优化的结果)。
ffplay/potplay/hls.js 播放全程静音
ios 1分钟前静音,1分钟后正常同步音频