音视频重新编码时间戳同步问题
在对音视频重新编码并需要进行同步的场景中,需要遵守几项基本原则(否则音视频就会卡顿,不流畅。以音频aac编码频率44.1k,视频h264编码25帧帧率为例):
1. 保证输入端的音视频帧到达间隔基本精确。音频aac每帧时长是23.2ms(1000*1024/44100),视频每帧时长是40ms(1000/25)。所以,用于编码的原始音频samples的到达频率(或从buffer中获取的频率)应该为441 samples/per channel/ per 10ms(每个样本假设16bits,即882字节/通道/10ms,如果原始音频采样率不是44.1k,编码前需要重新采样);原始视频帧到达频率(或从buffer中获取的频率)应该为1帧/per 40ms(视频帧率可能需要重新采样)。如果输出的音视频流不流畅,可先检查输入端音视频流的输入间隔情况。
2.保证输出端的音视频流时间戳使用同一参考系。比如音视频流都使用当前系统时间作为同一时间参考系,但音视频流可以有不同的系统时间起始点。比如音频流先开始于1492764087000 ms,视频稍后700ms开始于1492764087700ms。比如rtmp里面使用32位时间戳,则音视频流只能使用相对时间戳,接上例,音频时间戳增长到700ms的时候视频流才从0开始,表示视频流是从音频流的700ms处开始的,这样才能达到同步的效果。 另外一种时间戳方案是每个音视频帧按固定间隔增长,比如音视频时间戳都从0开始,音频每个aac帧增加23.2ms,每个视频帧增长40ms。正常情况下,音视频流是同时从0开始按相应各自间隔发送帧的,但也有视频流晚于音频流或音频流晚于视频流的情况。这种情况需要做时间戳同步,稍晚的流起始时间要根据超前的流的时间来设置。
3.保证交叉输出时音视频间隔基本精确。这里的输出端就完全等同于一个硬件编码器,只有保证交叉输出的音视频帧间隔稳定,才能保证播放端的流畅。比如rtmp,每个aac音频帧输出间隔应该在23ms左右,每个视频帧输出间隔应该在40ms左右,而且音视频帧是交叉输出。换句话说,每23ms要发送一个aac音频帧,每40ms发送一个视频帧(可以使用两个单独的线程来分别发送音视频流)。如果排除了上面的两个问题还是不能流畅播放,可以检查这个环节是否正常。
总之,重新编码并同步的这个环节,必须建立在数学测量的基础上。有错误或补充的地方,欢迎指出。
下面是一个实际项目中基于以上规则的调整实现版本:
实际环境中与上述假设条件不符的地方:
1.前端输入帧率变化,x264不能稳定输出每秒固定24/25帧。
时间戳调整方案:由标准的音视频固定帧间隔累加调整为按帧间实际时间偏移累加。如音频,不再按每帧间隔23ms去累加,原因是会出现系统时间间隔1s的情况下音频时间戳增加小于1s的情况;视频不再按每帧间隔40ms去累加,也改为实际帧间间隔,比如每次编码完之后每帧之间间隔是变化的,帧率可能不到24/25。最终实现音视频时间戳的同步。以系统绝对时间间隔来增加音视频时间戳本身就是同步的;如果使用其他人为制定的时间戳增长方案(比如上面的音视频按固定间隔递增),就需要再引入一个同步模块来处理音视频时间戳之间的递增偏移问题,比较麻烦也难于精确控制。该方法其实就是上面提到的第2条原则:音视频使用同一时间参考系。
项目中几种尝试过的错误的方案:
1. 上面标准的音视频帧间隔累加计算时间戳。这种情况会出现音视频时间戳偏移越来越大的问题,可能视频大于音频或者音频大于视频,时间戳会差距越来越大。
2. 视频流使用原始帧时间戳作为参考。此种方法也不可取,原因是原始帧的时间戳是基于原始视频流帧率的,你x264重新编码后,帧率已经不一样了。帧与帧之间的间隔也没有参考意义。