有人找到我,说他使用Adobe Premier工具剪辑mp4文件,这个文件在PR中播放不同步,但是使用vlc等播放器播放这个mp4都是同步的.
最简单的结论当然是PR兼容性不好咯. 但是作为一个音视频开发者,是不是能给出一个更进一步的结论呢,比如这个mp4的什么特性导致了PR工具不太灵光.
文件分析
同步问题总是和音视频时戳是相关联的,一般播放器播放都没问题,那么说明音视频时戳间的关联没有问题,先将时戳取出分析
|
|
这个mp4文件是由h264编码的视频和44100采样率的aac编码的音频组成的.它的帧率是25,视频时戳通过ffprobe打印的结果来看是很均匀的,音频则会在某些时间
点发生几十到上百毫秒的跳跃.什么是音频时间戳的跳跃?比如说这个文件音频是44100采样率的LC AAC
编码格式,这种编码的音频一帧采样个数frame_size
固定是1024,那么一帧音频数据的时长应该是:
|
|
也就是说一般情况下每帧的音频时戳差值是1024/44100
ms.
但现实情况下,总会有些文件的音视频时戳并不是这么打的,时戳经常可能跳跃,举个例子,直播时的采集系统一般是分开工作的,视频以25fps的时间正常采集, 并给每帧打上1/25秒增量的时戳,视频时戳非常均匀,但是音频采集中间某个点卡了一下,这帧音频错过了,且采集系统并没有补充这一帧,将会出现一帧的跳跃, 如果还是按照固定增量的方式打时间戳那么音视频要不同步了,所以这时候音频时戳参考外部时钟,也会有一帧的跳跃.
PR不同步原因猜测
PR是Adobe的商业软件,我们没办法从它的实现原理分析,只能对比测试,猜测一下原因.
使用音视频时戳完全均匀的mp4文件,PR是没有问题的,而面对这种音频时戳有跳跃的,它就无法和视频同步了,从它的时间轴线来看,它的音频总时间轴对应的并不是
mp4文件中的音频的时长,即最后一个音频包的pts减去第一个音频包的pts,而是总的samples时长, 也就是nb_samples/44100
.
那么合理的猜测是PR工具播放音频时是按照采样率去播放的,事实上很多工具播放音频都是按照采样率均匀连续送音频帧到声卡设备中播放, 这样不会造成音频中间的卡顿.而播放视频很可能是按照视频时戳播放的,由于音频中间有跳跃,那么累积误差下,这种播放方式也就不同步了.
视频同步到音频的播放原理
那么一般播放器播放这种视频文件是如何做到同步的呢,其实原理很简单,音视频同步,一言以蔽之,必须严格参考原始时戳.
下面通过一个很普遍的视频同步到音频的播放方式来说明一下播放器处理这种情况的同步原理.
一个音视频时戳不均匀的时间轴:
视频同步到音频是播放器常用的一种播放方式,为了能均匀播放音频,播放器会均与送入解码后的音频pcm
数据.
这时音频播放的时间轴并不是音频包本身的时戳了,因为音频包中间的时戳有间隙,如上图所示的gaps
, 这时按照samples播放我们称之为samples时间轴.而音视频的时戳我们称之为音视频时戳时间轴.
音频启动了播放,这时视频的播放需要与之同步,不能单独参考视频自己的时戳了,原因是因为音频播放参考的是samples时间轴,这个时间轴和音视频时间戳时间轴之间是有跳跃的.
那么播放器是怎么做的呢.一定时间间隔检查音频播放点,然后换算为音视频时间戳的值,通过这个值找到当前应该渲染的视频帧.换算流程如下:
- 取得音频播放点对应的音频帧的时戳和对应音频帧的内的samples偏移
- 该时戳加上偏移samples数量换算的时间间隔
- 得到的时戳值就是当前音视频时间轴的时戳,用这个时戳去寻找最接近的视频帧
修正方式
通过上面的原理和测试,要修正这个PR问题,我们需要把这个文件的音视频时戳调整一下.
现有的工具好像很难做到这个调整,一般的调节编辑工具都会尊重原始的音视频时戳,避免出现音视频不同步现象. 我们需要按照播放器的方式来调整这个媒体文件,但是不做转码,保留原始的音视频编码.调整步骤如下:
- ffmpeg接口demux一遍文件,存下所有音频包的音频原始时戳和音频包序号的映射,记为
std::map<audio_pts, audio_index>
- ffmpeg接口再次demux一遍文件,这次遍历每个音视频包
- 遍历中的音频包重新打新时戳, 第一个从0开始,后续时戳均匀递增,差值为
nb_samples/samplerate
- 遍历中的视频包根据视频时戳
video_pts
寻找第一个大于video_pts
的audio_pts
, 并取得audio_index
. - 也就是该视频包时戳"座落于"音频帧序号
[audio_index-1, audio_index)
之间 - 取得
audio_index-1
的audio_pts
,用video_pts-audio_pts
算出偏移offset - 重新给这个视频包打上新的时戳,这个时戳计算是,
audio_index-1
音频的新时戳加上上一步计算的offset
按照这个步骤重新生成一个不转码的mp4文件,导入PR工具中,一切都正常了.