最近在翻看以前写的文档,把这篇word文档复制下来,保留一下。
序号 |
版本 |
作者 |
描述 |
1 |
V0.1 |
YJ.Yan |
初始版本 |
2 |
V0.2 |
YJ.Yan |
添加方案细节描述以及可参考方案 |
1. 基本概念
a) NAT
网络地址转换(NAT,Network AddressTranslation)属接入广域网(WAN)技术,是一种将私有(保留)地址转化为合法IP地址的转换技术,它被广泛应用于各种类型Internet接入方式和各种类型的网络中。原因很简单,NAT不仅完美地解决了IP地址不足的问题,而且还能够有效地避免来自网络外部的攻击,隐藏并保护网络内部的计算机。
家庭用路由器就是采用这种技术。NAT还分4种类型:
(1) Full Cone
这种NAT内部的机器A连接过外网机器C后,NAT会打开一个端口.然后外网的任何发到这个打开的端口的UDP数据报都可以到达A。不管是不是C发过来的。如图所示:
(2) Address Restricted Cone
这种NAT内部的机器A连接过外网的机器C后,NAT打开一个端口。然后C可以用任何端口和A通信。其他的外网机器不行。如图:
(3) Port Restricted Cone
这种NAT内部的机器A连接过外网的机器C后,NAT打开一个端口。然后C可以用原来的端口和A通信,其他的外网机器不行。如图:
(4) Symmetric(对称形)
对于这种NAT。连接不同的外部Server,NAT打开的端口会变化。也就是内部机器A连接外网机器B时,NAT会打开一个端口,连接外网机器C时又会打开另外一个端口。
b) 打洞(穿越)
如上面NAT类型的描述,因为只有A主动连接了C,C才可以透过NAT发送数据到A。如果两个处在NAT环境中的主机要相互连接并传输数据(透传)的时候,就需要一个中间人的角色:Server。所以打洞的过程如图所示:
主要流程是这样的:
(1)如果A想与B通信;
(2)A首先连接C,C得到A的外网NAT A的地址和端口;
(3)B也要连接C,C得到B的外网NAT B的地址和端口;
(4)A告诉C说我要和B通讯;
(5)C通过NAT B发信息给B,告诉B A的外网NAT A的地址和端口;
(6)B向NAT A发数据包(肯定会被NAT A丢弃,因为NAT A上并没有 A->NAT B 的合法session),但是NAT B上就建立了有B->NAT A的合法session了;
(7)B发数据包给C,让 C 通知 A,我已经把洞打好了;
(8)A接受到通知后向 B 的外网发NB数据包,这样就不会被丢弃掉了。因为对于NAT B来说,它看到的是A的外网NAT A的地址,而通过第6步,B已经让NAT A成为NAT B的合法通信对象了。所以当NAT A发数据包给NAT B时,NAT B就会接收并转发给B;
c) STUN
STUN的全称是Simple Traversal of UDP Through NAT,即UDP对NAT的简单穿越方式。应用程序(即STUN CLIENT)向NAT外的STUN SERVER通过UDP发送请求STUN 消息询问自身的转换后地址,STUN SERVER收到请求消息,产生响应消息,响应消息中携带请求消息的源端口,即STUN CLIENT在NAT上对应的外部端口。然后响应消息通过NAT发送给STUN CLIENT,STUN CLIENT通过响应消息体中的内容得知其在NAT上对应的外部地址,并且将其填入以后呼叫协议的UDP负载中,告知对端,同时还可以在终端注册时直接注册这个转换后的公有IP地址,这样就解决了穿越NAT的通信建立问题以及作为被叫时的问题。本端的接收地址和端口号为NAT外的地址和端口号。由于通过STUN协议已在NAT上预先建立媒体流的NAT映射表项,故媒体流可顺利穿越NAT。
PS:从RFC5389开始,STUN不再是RFC3489那样作为一个NAT穿越的完全解决方案了。
STUN is not a NAT traversal solution by itself. Rather, it is a tool to be used in the context of a NAT traversal solution. This is an important change from the previous version of this specification (RFC3489), which presented STUN as a complete solution. |
d) TURN
TURN方式解决NAT问题的思路与STUN相似,也是私网中的客户端通过某种机制预先得公网上的服务地址,不同的地方在于:STUN方式得到的地址为出口NAT上外部地址,TURN方式得到地址为TURN Server上的公网地址,然后在报文净载中所要求的地址信息就直接填写该公网地址。
TURN的全称为Traversal Using Relay NAT,即通过Relay方式穿越NAT。TURN解决了STUN应用无法穿透对称NAT(Symmetric NAT)的问题,但是所有报文都必须经过TURN Server转发,所以又增大了包的延迟和丢包的可能性。
2. 天猫魔盒家庭监控APK分析
a) 抓包分析
天猫魔盒的IP为:
抓包过程为:启动家庭监控——>关闭家庭监控
此时手机端和天猫魔盒不属于同一个网段。
网络包的靠前部分为:
除去TCP的握手过程,可以清晰的看到STUN协议的包,经过查询42.156.208.7是阿里巴巴的服务器IP,所以可以断定该服务器是STUN服务器。
再仔细观察这个包,其中的NONCE字段,表明了他们采用了RFC5389的STUN协议,而CHANNEL-NUMBER则进一步表明了他们使用的是TURN协议来进行网络透传的。
接下去让我们再继续看传输视频流的包:
所有的ChannelData包都是以0x2080开头的,通过和手机端的抓包(这里不再贴图)对比,发现0x2080就是他们视频流的网络封包。所以,这里可以断定他们是使用TURN协议来进行网络透传的。
虽然有经过服务器中转,但是视频的实时性还是不错的,实际测试中,延时大概在1S左右。
我们再来看一看手机端和天猫魔盒属于同一网段时候,手机端的抓包:
魔盒的IP是131,手机的是134,如上可以看出,当两者处于同一网段的时候,他们不再通过TURN中转,而是直接以UDP点对点的方式进行视频流传输,视频流网络包也是以0x2080开头,从而验证了上面所说的0x2080包头属于视频流的猜想。
综上所述:对于天猫魔盒和阿里TV助手配合实现的家庭监控方案,我们得到了如下分析:
(1)NAT穿透方面,采用的是STUN+TURN的方式,对于视频流采用服务器中转。
(2)内网直接采用UDP方式进行视频流传输。
b) APK反编译分析
使用apktool对阿里TV助手(Remote.apk)进行反编译之后,有如下文件:
在AndroidManifest.xml中,关于家庭监控有如下内容:
其中safehome与家庭监控模块的有关,所以我们先开始查看与safehome相关的smali目录“smali\com\yunos\safehome”(smali是apktool反编译出来的伪代码):
在monitor/ VideoMonitorActivity.smali的伪代码中,有如下片段:
其中可以发现,视频方面是采用mmpc/avengine/video/目录中的方法。
接下去让我们看看mmpc中的内容:
从这个目录中,我们不难看出,avengine与视频相关,netengine与网络相关。现在分别贴出avengine和netengine的目录结构:
目录结构已经验证了我们的猜想。在VideoEngine.smali以及P2PConnector.smali中,我们都看到这么一句伪代码:
在mmp/util/LoadLibraryUtil的LoadMmpc()函数中,我们又可以看到如下伪代码:
所以,我们可以推断,libmmpc.so是这些模块的关键库,接下去,我们就将libs/libmmpc.so通过nm命令将其中的函数打印出来。
其中我们可以看到很多关于RTP/RTCP、VideoEngine、P2PTransport等等与网络传输以及视频编解码相关的函数名。
综上所述,我们可以推出天猫手机端APK的几个技术点:
(1)采用RTP传输视频流
(2)采用so库进行视频编解码和NAT穿透
(3)对STUN/TURN协议的实现是自己组包的
3. 初定方案
(1)实时视频流采集
方案一:在Camera中对setPreviewCallback实现onPreviewFrame接口,实时截取每一帧视频流数据。
通过试验,传输一帧数据比较大,对网络质量要求高。
方案二:使用MediaRecorder,在SetoutputFile函数中绑定LocalSocket实现
使用LocalSocket可以获取硬件编码后的视频流,但是不是实时视频流,需要在视频流中添加SPS和PPS重新编码并通过RTP打包发送出去。
方案三:流媒体服务器方式,利用ffmpeg或GetStreamer等获取Camera视频
(2)压缩编码
方案一:不编码,直接通过Socket传输原始YUV420SP视频帧
方案二:JPEG编码,将原始YUV420SP视频帧压缩转换为JPEG格式,JPEG传输
方案三:H.264/AVC.将原始YUV420SP视频帧压缩成H.264再传输
方案四:MPEG4.将原始YUV420SP视频帧压缩成MPEG4再传输
(3)数据传输
方案一:Socket传输
方案二:HTTP传输
方案三:RTP/RTSP传输
方案四:流媒体服务器方式,如live555等
Live555可以将已有的视频文件编码成可播放的RTP视频流,但是对于实时视频流的编码是否支持还未知。
(4)NAT穿透
方案一:使用STUN+TURN方式进行NAT穿透(可以使用restund开源方案搭建STUN/TURN服务器)
(5)解码与播放
方案一:使用VLC/JAVACV等第三方库解码后使用SurfaceView进行播放。
方案二:直接使用MediaPlayer(需要底层芯片支持解码)
4. 可参考开源方案以及第三方库
(1)DroidIPCam(采用了libjingle库)
http://code.google.com/p/ipcamera-for-android/
(2)spydroid-ipcamera
http://code.google.com/p/spydroid-ipcamera/
(3)libjingle
https://code.google.com/p/webrtc/source/browse/#svn%2Ftrunk%2Ftalk