17 April 2014

IMG-THUMBNAIL

##1. RTP 实时传输协议(Real-time Transport Protocol,RTP)是一个网络传输协议,它是由IETF的多媒体传输工作小组1996年在RFC 1889中公布的。RTP协议详细说明了通过互联网上传递音频和视频的标准数据包格式。

IMG-THUMBNAIL

每一个RTP数据报都由头部(Header)和载体(Payload)两个部分组成,其中头部前12个字节(96 bit)的含义是固定的,而负载则可以是音频或者视频数据。

  • Ver.(2 bits)是目前协定的版本号码,目前版号是 2。
  • P(1 bit)是用于RTP 封包(packet)结束点的预留空间,视封包是否需要多余的填塞空间。
  • X(1 bit)是否在使用延伸空间于封包之中。.
  • CC(4 bits)包含了 CSRC 数目用于修正标头(fixed header).
  • M (1 bit) 是用于应用等级以及其原型(profile)的定义。如果不为零表示目前的资料有特别的程序解译。
  • PT(7 bits)是指payload的格式并决定将如何去由应用程式加以解译。
  • SSRC 是同步化来源。

实时传输控制协议(Real-time Transport Control Protocol 或RTP Control Protocol或简写RTCP)是实时传输协议的一个兄弟协议。RTCP为RTP媒体流提供信道外控制。RTCP本身并不传输数据,主要用来和RTP一起协作将要发送的音频和视频数据打包发送。RTCP的主要功能是为RTP所提供的服务质量提供反馈,保证流媒体发送实时同步。

RTP的同步控制是通过RTCP协议的Sender Report和Receiver Report实现。

  • Sender Report:发送端报告,所谓发送端是指发出RTP数据报的应用程序或者终端,发送端同时也可以是接收端。
  • Receiver Report:接收端报告,所谓接收端是指仅接收但不发送RTP数据报的应用程序或者终端。

##2. 基于sipdroid完成RTP包解析播放 sipdroid默认建立链接之后会判断当服务器是否是sipdroid官方提供的服务器,如果不是,则只会建立音频通话,不建立视频通话。注释掉该判断语句,发现它实现了发送RTP流媒体功能,通过与linphone的通话,能够在linphone端看到视频信息。然而,无法播放linphone发送的视频信息。又通过查看代码,发现播放视频的方法是通过RTSP接收。

    if (Receiver.call_state == UserAgent.UA_STATE_INCALL && socket == null
            && Receiver.engine(mContext).getLocalVideo() != 0
            && Receiver.engine(mContext).getRemoteVideo() != 0 && PreferenceManager.getDefaultSharedPreferences(this).getString(org.sipdroid.sipua.ui.Settings.PREF_SERVER, org.sipdroid.sipua.ui.Settings.DEFAULT_SERVER).equals(org.sipdroid.sipua.ui.Settings.DEFAULT_SERVER)))

 mVideoFrame
         .setVideoURI(Uri.parse("rtsp://"
         + Receiver.engine(mContext).getRemoteAddr() + "/"
         + Receiver.engine(mContext).getRemoteVideo()
         + "/sipdroid"));

sipdroid播放视频流还需要建立RTSP会话。而linphone直接发送的是RTP包,所以sipdroid无法播放linphone的视频。在此之前一直使用WireShark分析RTSP建立,结果就是没找到建立过程。后来看源码才发现。。。上面提到的代码分别是在包org.sipdroid.sipua.ui内的类CallScreen的函数onResume中和类VideoCamera的函数onResume中。

但是现在依然有疑问,上面的代码是通过直接请求远程客户端建立RTSP请求,通过MediaPlayer播放。并没有关系到服务器,那么RTSP是怎么建立的?而且,它专门指定要自己的服务器才能去建立视频连接,既然RTSP建立又没有关系到服务器,这个逻辑又是为什么?而且这两个疑问又互相矛盾,如果大家有想法,不妨屈尊指导一下学渣

抛开上面的问题不管,只要自行进行视频解码,还是可以播放的。通过从rtp_socket读取包,发现每次都能读取到1414字节的数据。应该可以证实是从linphone传来的数据,包大小也正常。下面开始着手解包和播放。

整个RTP包的实现就是基于UDP进行传输的。也可以从代码的实现验证这一点,RtpSocket类内部拥有UDPDatagramPacket数据报。RTP可以认为是为UDP加了12字节协议包。类RtpPacket提供自动解析的能力。下面是解析后的结果和协议头的对比。

  #   RTP协议   抓取到的内容   描述  
  1   Version   2   版本号,为2  
  2   hasPadding   false   没有加塞空间  
  3   hasExtension   false   没有额外空间  
  4   CscrCount   0   Cscr数目  
  5   hasMarker   false   没有特别程序解释  
  6   PayloadType   103   Payload的格式 h263-1988  
  7   SequenceNumber   325      
  8   Timestamp   468900      
  9   Sscr   488792334      
  10   CscrList          
  11   Payload          
  12              
  13              

##3. RTP解包

由于前期调研的疏忽,给自己挖了一个坑。绕了好多弯路。前期通过查看论文,了解到目前流行的方法都是通过RFC 3984进行开发。通过RTP发送H264格式的视频。H264格式的视频数据由分隔符00000001、NAL和VCL组成。进行RTP封包就是去掉分隔符进行发送,解包的时候再加上分隔符即可。还看了C++和Java实现的RTP解包方法,愣是和sipdroid的封包方法对不上。后来才意识到,我看的是H264的,而sipdroid用的是H263。

经过调研,决定使用libsteaming基于RTSP开发。Android支持H264的编码和解码,但是没有直接提供编码和解码接口。编码只能使用MediaRecorder编码到文件当中,而解码更是只能依靠MediaPlayer播放文件时才能被调用解码器。所以使用libstreaming编码,直接使用MediaPlayer进行RTSP播放即可。如果要自行封装RTP包的话,还需要跨平台编译H264的解码器。

##乱续、同步


参考文献
  • 【1】RTMP/RTP/RTSP/RTCP的区别 - FrankieWang008的专栏
  • 【2】RFC3984 RTP Payload Format for H.264 Video
  • 【3】鲍轩. 基于Android手机音视频监控的软件研发与同步实现[D]. 杭州电子科技大学, 2013年10月.
  • 【4】fly2700. FU-A分包方式,以及从RTP包里面得到H.264数据和AAC数据的方法. http://www.cnweblog.com/fly2700/archive/2012/02/23/319718.html
  • 【5】jasonhwang. Wireshark Lua: 一个从RTP抓包里导出H.264 Payload,变成264裸码流文件(xxx.264)的Wireshark插件. http://blog.csdn.net/jasonhwang/article/details/7359095
  • 【6】mcodec, H264解码器源码(Android 1.6 版)[EB/OL], http://www.cnblogs.com/mcodec/articles/1780598.html.
  • 【7】熊荣海,刘立柱. H263码流的RTP封装的研究与实现.

原文链接:实时传输协议RTP,转载请注明来源!

EOF