rtp,rtcp网络音视频写入(avi)文件,音视频同步方案

来源:互联网 发布:java log4j 中文乱码 编辑:程序博客网 时间:2024/06/06 09:13

 

一、背景

将网络中的音视频流抓取下来并写入到avi文件,要做到使用其他播放器直接播放出来,音视频是同步的。

二、关于avi

Avi文件结构(解析)我这里就不多讲了,网络上资料多得是。但是要知道播放器在播放avi文件的时候,会将音频视频分开,使用各自的播放时钟速率播放(音频是使用采样率和量化精度, 视频是帧率),而avi文件本身是无法存放timestamp的,所以在写文件之前通过网络协议对音视频做同步,然后写入avi是根本无效的。这里我再解释一下,就是说avi文件里面存放音频块视频块的顺序位置都是无所谓的,哪怕前面全是音频,后面全是视频,播放出来都是一样的,所以在写avi之前做同步,按顺序把同步好的音频和视频写入avi,播放出来的效果,和没有做同步直接写文件的结果是一样。

原因,我一开始就说了,这里再强调一下,是因为播放文件的时候,把音视频分离开了,本来有序的东西,也无意义了。

(播放其他文件是不是一样的,我没测试过)

 

三、解决方案

通过上面的描述知道,直接写avi文件是不行的。那么下面我给出一种解决方案,以rtp,rtcp为例。

         一句话描述:以音频为主流,视频为从流,通过网络NTP, timestamp做同步,根据相邻两个NTP直接的音频播放时间(注意是播放时间),计算出应该有多少帧视频数据,然后对现有的视频做补帧,或者抽帧

         Rtp里面只承载媒体流,时间戳(这个是相对时间,可以做流内同步),以及源等信息,并没有同步信息。Rtcp里面是有的,rtcp中SR包里面有NTP时间,这个时间是可以可以用来做音视频同步的,另外rtcp里面的SDES包里面有CNAM,这个是全局唯一的,表示同一rtp参加者唯一标识(这里,可以理解为,音视频的关联点,音频rtp,和视频rtp,如果它们是有关联的,音视频是吻合的,那么rtcp里面的CNAME就会一样),然后根据rtcp中的ssrc关联到具体的rtp,那么就把音频rtp和视频rtp关联起来了。这里面有几个重要的东西,需要自行去学习了解, rtp的timestamp, rtcp的NTP,

Rtcp的CNAME, SSRC,把这几个了解清楚了,并且获取到了,那么就完成了下面解决方案的准备工作。(如果其他网络协议,也是一样的)

         将音频流和视频流分开处理(怎么处理,看项目需要,也许需要解码,看具体要求),另外视频需要做组包,音频不用,然后将处理后的音视频存入缓存(最好是开辟两个缓存,一个用于音频,一个用于视频)中分析。这里处理后的音视频每包(帧)都要有timestamp信息(可以用结构体封装起来  header + data),音视频直接会有NTP数据包做间隔。 如下:

         Header : {

                   Cmd:  命令(AUDIO, VIDEO, NTP等)

                   Char*pdata:  具体的数据

}

         缓存1: (header+data), (header+data),(header+data)。。。

缓存2: (header+data), (header+data),(header+data)。。。

 

上面的缓存数据块,中间是会有NTP数据块做间隔的(NTP数据块要上层传入)。

分析:对于缓存1中的NTP, 缓存2中的NTP,  找到第一个相等(其实不会相等,相近就行,允许差几十或上百毫秒),做为基准,然后找第二个NTP相等的点,那么理论上要求这两个缓存中的(NTP2-NTP1)中的流播放时间相等(是播放时间),那么现在以音频为主流,算出NTP2-NTP1中所有音频包的总byte数(audiototal),playtime = audiototal / (采样率 * 量化精度 * 通道数 / 8) ,playtime就是播放时间(秒), 然后通过playtime,算出应该有多少帧视频与之对应,totalframe = playtime * fps 。 现在再来处理视频,看计算出来的totalframe和实际NTP2-NTP1中的视频帧数(actualframe)是不是一样的. 如果actualframe< totalframe,那么就要做补帧(方法在后面),如果是大于,就要做抽帧(方法在后面)。这样处理过后,把NTP1~NTP2中的所有音视频数据包写入avi文件中,然后,就是循环了,一直这样做,待结束为止。

这样在播放的时候,虽然音视频按各自的的播放速率,但是播放时间也是匹配(同步了的)。

另外,对于第一个基准NTP前的数据,和最后一个NTP后的数据,处理方法其实也是一样的,通过对视频的抽帧补帧,让音频视频的播放时间相同。

补帧方法:对于avi文件,这个很简单,只要在后面的index中加入空的index块(lenth=0)就可以了,或者就在要插入的位置,找相邻的帧,复制一下也可以的(建议不要复制I帧)。

抽帧方法:写个方法,随机在NTP1~NTP2中去掉一些帧就行了(如果有I帧,P帧,记住不要抽调I帧)。

 

 

以上是解决网络音视频流写入avi文件,且做到播放同步的解决方案。

 

转载请标明出处..


1 0
原创粉丝点击