PCR同步在非硬件精确时钟源的情况还是谨慎使用,我起初采用PCR同步就会出现,随着时间的推移,软件模拟的时钟不精确会导致视频出现延时或者音视频不同步。
最近研究了FFMPEG的同步技巧,觉得其精妙绝伦,完全不用担心随着时间的推移会发生如上问题!下面简述下FFMPEG下如何进行音视频同步的吧!
FFMPEG有三种同步方式,视频同步音频,音频同步视频,同步到外部时钟!
第三种,同步到外部始终也就是PCR同步和我原来说的那中同步方式,一样!
用的最多的还是,视频同步音频,为什么呢?音频的采样率是固定的,若音频稍有卡顿,都会很明显的听出来,反则视频则不如此,虽然表面上说的是30P,不一定每一帧的间隔就必须精确到33.33ms,因为人肉眼是观察不出来的,所以视频的帧率可以是动态的,并不是严格标准的!
废话少说了!用视频同步音频,做法很简单!首先,音频线程只管自己独立解码播放。视频线程在显示之前只需要检测视频PTS是否大于音频PTS,若大,则等待音频PTS》=视频PTS,若小,则直接播放,小太多则可以直接丢弃(跳帧)。做法就如此简单!但前提是你编码器一定要打好正确的PTS,若没有则只有自己伪造PTS了!
音视频同步和帧率控制其实是一个东西。我们先不管音视频同步是什么,我们先来看看如何进行帧率控制。明白了帧率控制,音视频同步那些都一通百通。一些基本的音视频术语我就不介绍了,大家自己百度吧!
1、帧率控制
帧率控制的方法有千万种,最2的方法无非是每解码/显示一帧就进行延时,为了方便我们在进行帧率控制的同时能够理解音视频同步,我在此采用PCR同步的方式来进行帧率控制。网上关于PCR同步的原理讲了一大堆,有些很是难懂,一点儿也不通俗,我这里来给大家把晦涩的理论以最通俗的方式表达出来。还希望大家多多指教!
拿1280x720@30p的视频源来做理解。30P也就是说每秒钟30帧,也就是每一帧需要1/30*1000ms大概也就是每隔33.33ms就必须显示一帧。
要想知道如何正确的进行解码,就必须先了解编码端是如何工作的!一般编码器会以27MHZ的时钟来进行编码,这些都不重要,重要的就是,编码器一般默认会每隔30ms会发送一次PCR信息,这里的PCR信息就很重要了,他是我们在解码端解码进行帧率控制的时间基点,同时也是我们以后在进行同步校准的校准基点。
说了这么多,那么我就那个PCR信息来给大家分析分析。PCR信息是33bit组成的一个INT64_T的数据,从解复用器里面出来我们可以得到一个很庞大的数字,看这个我们当然看不太懂!但是如果知道这个数字如何生成的那就好理解多了!
PCR信息说白了就是给视频的时间戳信息,比如一部电影是从 (00:01:23:033)时 : 分 : 秒 : 毫秒
开始,那么这个时间基点生成的PCR信息就是
(((00*60+1)*60+23.033)90K)%2^33。90K为27M,300分频的结果。刚刚说了PCR会每30ms更新一次,那么PCR每次递增的数值就为0.03090K=2700,这和PTS的值原理是相同的,这里先提一下,其实这个增量也不重要。我们需要的知识第一个PCR值就OK,但是如果考虑到后期校准,还是要用到以后的PCR值的。这里先不管校准的问题!
说了PCR,还有个值是我们需要的,那就是PTS。其实对于硬解码器来说DTS信息我们根本就不需要管他,我们只需要一帧一帧的把数据送进去,顺便把每一帧的PTS信息送进去,解码器送出来的就是排列好了PTS信息的帧了,其他解码器不知道至少RK3288是这样的。大家可以试着把解复用后的每一帧的PTS打印出来,你会发现在解复用后一般是这样排列的9000
3000 6000 18000 12000
15000.。。。。。。这种是AVC编码的使用的是预测编码决定的,先不管他,你只管这样把没一帧依次送入解码器,解码器解码输出后自然就排列成3000 6000 9000 12000 15000 18000这才是我们需要的PTS!至于什么是PTS,实际上和PCR原理差不多,但是有个关键的地方PTS的增量值可不是默认的30ms了,他是由视频的帧率来决定的!说道重要的地方了哈!根据上面PCR的原理,如果是30p的视频那么每一帧就是1/30这么多的增量,再乘90K=3000。
说透了,我们这里就是利用这个PTS值来进行同步顺便进行帧率控制!
关键的地方来了!
如果视频流现在来了,我们先获取到第一个PCR值为1230000,我们现在马上在解码器端重建一个90K的时钟!这就是关键所在,至于如何重建90K的时钟,说白了就是开一个定时器,定时时间为1/90K(11.11us),每隔11.11us我们就把PCR计数值+1,同时这时候解码器也在工作,试想一下,如果是30P的视频,也就是33.33ms显示一次,那么当过了33.33ms后,PCR的数值加到好多了呢?没错就是33.33ms/11.11us=3000,这个增量不是和PTS的增量一摸一样!这时候你只需要在解码线程里判断当前帧的PTS是不是和这个PCR相等,如果相等就显示,如果PCR大可以丢弃当前帧,也就是说的跳帧,如果PCR小说明解码快了,这个时候就可以等待定时器线程到PCR==PTS。
这样就很巧妙的解决了帧率控制的问题了!同理,音视频同步也可以这样!你可以让音频的PTS去和PCR对比!其实大多数情况下都是以视频同步音频,音频解码不用管它,直接解码播放就OK了,你只需要进行帧率控制就OK了!同时注意随着时间的推移有可能出现延时,那么这个时候就需要重新来获取PCR来更新定时器线程里面的PCR基值了!
原作者:jingjin221