基于移动平台的多媒体框架——移植Live555到Android上
live555是一个处理流媒体传输对c++库,再Mplayer与vlc中都有用到。我们计划将其加入到自己编写对Android上的播放器中作为流媒体模块,首先就需要将
这个库移植到Android上。
方案I:
最近在做Android上的多媒体开发,需要在Android上移植live555,因为我算是Android上多媒体开发的新手,于是在网上找各种资料,大致的做法都是:
1. 首先在官网下载live555对源码并解压。
2. 新建一个Android工程,将源码文件放到一个该工程的jni目录下,如:jni/live。
3. 新建jni/Android.mk文件作为Makefile。将需要编译对源文件加入到LOCAL_SRC_FILES变量,将需要引用对头文件加入到LOCAL_C_INCLUDES,编译过程中
会提示需要参数:-fexceptions,于是加入参数LOCAL_CPPFLAGS += -fexceptions。
内容如下:
4. 新建jni/Application.mk文件。由于live555需要引用stl,所以加入:
APP_STL := gnustl_shared
5. 运行ndk-build就可以得到live555库
补充:我已在Android上移植过ffmpeg,并且写了简单的测试程序,可以正常的调用生成的ffmpeg库文件!!!
因移植过程中还是出现了一些错误,我顺便把移植的过程写的详细点,便于他人参考。
1. 下载了live555源码,日期是12/04/04,用的ndk版本是r5b。
2.预备工作,先用标准的方法make一下,确定你的源码是可以编译过的。
01../genMakefiles linux
02.make
[plain] view plaincopy
01../genMakefiles linux
02.make
马上就看到成功的结果了,这时不要急得移植。移植是交叉编译了,咱们先不用交叉编译,用gcc编译看看会不会。
了解live555的基本结构之后就可以执行:
01.g++ BasicUsageEnvironment/*.cpp liveMedia/*.cpp mediaServer/*.cpp UsageEnvironment/*.cpp ./groupsock/*cpp -
IBasicUsageEnvironment/include -IliveMedia/include -IBasicUsageEnvironment/include -Igroupsock/include/ -IUsageEnvironment/include -
DSOCKLEN_T=socklen_t -shared -o live555.so
[plain] view plaincopy
01.g++ BasicUsageEnvironment/*.cpp liveMedia/*.cpp mediaServer/*.cpp UsageEnvironment/*.cpp ./groupsock/*cpp -
IBasicUsageEnvironment/include -IliveMedia/include -IBasicUsageEnvironment/include -Igroupsock/include/ -IUsageEnvironment/include -
DSOCKLEN_T=socklen_t -shared -o live555.so
这样在本地就生成一个so了。
3. 跟本地一样,如果你了解了ndk的用法,写个简单的mk文件就可以移植了。建工程什么的在上面说了,我就把mk文件贴出来给大家参考一下好了。为了省事
,我就建了一个Android.mk文件。写的过程就是碰到什么问题,就改改加加什么参数。(这次连Application.mk都没有加就过了。。。)
参考的Android.mk文档是:http://blog.csdn.net/baby313/article/details/7289489
不幸的是,我生成live555的时候出错了:
Compile++ thumb : live555 <= GroupEId.cpp
/home/hu/android-ndk-r7/samples/vLive//jni/./live/groupsock/GroupEId.cpp:20:23: error: GroupEId.hh: No such file or directory
/home/hu/android-ndk-r7/samples/vLive//jni/./live/groupsock/GroupEId.cpp:21:21: error: strDup.hh: No such file or directory
/home/hu/android-ndk-r7/samples/vLive//jni/./live/groupsock/GroupEId.cpp:26: error: 'Scope' has not been declared
。。。
于是上网查资料,怀疑是脚本写错了(现在发现,应该是live555版本的差异引起的),于是接着上网查资料
在苦苦查询中找到了,一个方法:
方法很简单,在live555源码中写一个Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
BasicUsageEnvironment/BasicHashTable.cpp \
BasicUsageEnvironment/BasicTaskScheduler.cpp \
BasicUsageEnvironment/BasicTaskScheduler0.cpp \
BasicUsageEnvironment/BasicUsageEnvironment.cpp \
BasicUsageEnvironment/BasicUsageEnvironment0.cpp \
BasicUsageEnvironment/DelayQueue.cpp \
UsageEnvironment/HashTable.cpp \
UsageEnvironment/UsageEnvironment.cpp \
UsageEnvironment/strDup.cpp \
groupsock/GroupsockHelper.cpp \
groupsock/GroupEId.cpp \
groupsock/inet.c \
groupsock/Groupsock.cpp \
groupsock/NetInterface.cpp \
groupsock/NetAddress.cpp \
groupsock/IOHandlers.cpp \
liveMedia/our_md5.c \
liveMedia/our_md5hl.c \
liveMedia/rtcp_from_spec.c \
liveMedia/AC3AudioRTPSink.cpp \
liveMedia/AC3AudioRTPSource.cpp \
liveMedia/AC3AudioStreamFramer.cpp \
liveMedia/ADTSAudioFileServerMediaSubsession.cpp \
liveMedia/ADTSAudioFileSource.cpp \
liveMedia/AMRAudioFileServerMediaSubsession.cpp \
liveMedia/AMRAudioFileSink.cpp \
liveMedia/AMRAudioFileSource.cpp \
liveMedia/AMRAudioRTPSink.cpp \
liveMedia/AMRAudioRTPSource.cpp \
liveMedia/AMRAudioSource.cpp \
liveMedia/AudioInputDevice.cpp \
liveMedia/AudioRTPSink.cpp \
liveMedia/AVIFileSink.cpp \
liveMedia/Base64.cpp \
liveMedia/BasicUDPSink.cpp \
liveMedia/BasicUDPSource.cpp \
liveMedia/BitVector.cpp \
liveMedia/ByteStreamFileSource.cpp \
liveMedia/ByteStreamMultiFileSource.cpp \
liveMedia/DarwinInjector.cpp \
liveMedia/DeviceSource.cpp \
liveMedia/DigestAuthentication.cpp \
liveMedia/DVVideoFileServerMediaSubsession.cpp \
liveMedia/DVVideoRTPSink.cpp \
liveMedia/DVVideoRTPSource.cpp \
liveMedia/DVVideoStreamFramer.cpp \
liveMedia/FileServerMediaSubsession.cpp \
liveMedia/FileSink.cpp \
liveMedia/FramedFileSource.cpp \
liveMedia/FramedFilter.cpp \
liveMedia/FramedSource.cpp \
liveMedia/GSMAudioRTPSink.cpp \
liveMedia/H261VideoRTPSource.cpp \
liveMedia/H263plusVideoFileServerMediaSubsession.cpp \
liveMedia/H263plusVideoRTPSink.cpp \
liveMedia/H263plusVideoRTPSource.cpp \
liveMedia/H263plusVideoStreamFramer.cpp \
liveMedia/H263plusVideoStreamParser.cpp \
liveMedia/H264VideoFileServerMediaSubsession.cpp \
liveMedia/H264VideoFileSink.cpp \
liveMedia/H264VideoRTPSink.cpp \
liveMedia/H264VideoRTPSource.cpp \
liveMedia/H264VideoStreamDiscreteFramer.cpp \
liveMedia/H264VideoStreamFramer.cpp \
liveMedia/HTTPSink.cpp \
liveMedia/InputFile.cpp \
liveMedia/JPEGVideoRTPSink.cpp \
liveMedia/JPEGVideoRTPSource.cpp \
liveMedia/JPEGVideoSource.cpp \
liveMedia/Locale.cpp \
liveMedia/Media.cpp \
liveMedia/MediaSession.cpp \
liveMedia/MediaSink.cpp \
liveMedia/MediaSource.cpp \
liveMedia/MP3ADU.cpp \
liveMedia/MP3ADUdescriptor.cpp \
liveMedia/MP3ADUinterleaving.cpp \
liveMedia/MP3ADURTPSink.cpp \
liveMedia/MP3ADURTPSource.cpp \
liveMedia/MP3ADUTranscoder.cpp \
liveMedia/MP3AudioFileServerMediaSubsession.cpp \
liveMedia/MP3FileSource.cpp \
liveMedia/MP3HTTPSource.cpp \
liveMedia/MP3Internals.cpp \
liveMedia/MP3InternalsHuffman.cpp \
liveMedia/MP3InternalsHuffmanTable.cpp \
liveMedia/MP3StreamState.cpp \
liveMedia/MP3Transcoder.cpp \
liveMedia/MPEG1or2AudioRTPSink.cpp \
liveMedia/MPEG1or2AudioRTPSource.cpp \
liveMedia/MPEG1or2AudioStreamFramer.cpp \
liveMedia/MPEG1or2Demux.cpp \
liveMedia/MPEG1or2DemuxedElementaryStream.cpp \
liveMedia/MPEG1or2DemuxedServerMediaSubsession.cpp \
liveMedia/MPEG1or2FileServerDemux.cpp \
liveMedia/MPEG1or2VideoFileServerMediaSubsession.cpp \
liveMedia/MPEG1or2VideoHTTPSink.cpp \
liveMedia/MPEG1or2VideoRTPSink.cpp \
liveMedia/MPEG1or2VideoRTPSource.cpp \
liveMedia/MPEG1or2VideoStreamDiscreteFramer.cpp \
liveMedia/MPEG1or2VideoStreamFramer.cpp \
liveMedia/MPEG2IndexFromTransportStream.cpp \
liveMedia/MPEG2TransportFileServerMediaSubsession.cpp \
liveMedia/MPEG2TransportStreamFramer.cpp \
liveMedia/MPEG2TransportStreamFromESSource.cpp \
liveMedia/MPEG2TransportStreamFromPESSource.cpp \
liveMedia/MPEG2TransportStreamIndexFile.cpp \
liveMedia/MPEG2TransportStreamMultiplexor.cpp \
liveMedia/MPEG2TransportStreamTrickModeFilter.cpp \
liveMedia/MPEG4ESVideoRTPSink.cpp \
liveMedia/MPEG4ESVideoRTPSource.cpp \
liveMedia/MPEG4GenericRTPSink.cpp \
liveMedia/MPEG4GenericRTPSource.cpp \
liveMedia/MPEG4LATMAudioRTPSink.cpp \
liveMedia/MPEG4LATMAudioRTPSource.cpp \
liveMedia/MPEG4VideoFileServerMediaSubsession.cpp \
liveMedia/MPEG4VideoStreamDiscreteFramer.cpp \
liveMedia/MPEG4VideoStreamFramer.cpp \
liveMedia/MPEGVideoStreamFramer.cpp \
liveMedia/MPEGVideoStreamParser.cpp \
liveMedia/MultiFramedRTPSink.cpp \
liveMedia/MultiFramedRTPSource.cpp \
liveMedia/OnDemandServerMediaSubsession.cpp \
liveMedia/OutputFile.cpp \
liveMedia/PassiveServerMediaSubsession.cpp \
liveMedia/QCELPAudioRTPSource.cpp \
liveMedia/QuickTimeFileSink.cpp \
liveMedia/QuickTimeGenericRTPSource.cpp \
liveMedia/RTCP.cpp \
liveMedia/RTPInterface.cpp \
liveMedia/RTPSink.cpp \
liveMedia/RTPSource.cpp \
liveMedia/RTSPClient.cpp \
liveMedia/RTSPCommon.cpp \
liveMedia/RTSPServer.cpp \
liveMedia/ServerMediaSession.cpp \
liveMedia/SimpleRTPSink.cpp \
liveMedia/SimpleRTPSource.cpp \
liveMedia/SIPClient.cpp \
liveMedia/StreamParser.cpp \
liveMedia/uLawAudioFilter.cpp \
liveMedia/VideoRTPSink.cpp \
liveMedia/WAVAudioFileServerMediaSubsession.cpp \
liveMedia/WAVAudioFileSource.cpp \
impure_ptr_hack.cpp
LOCAL_SHARED_LIBRARIES := libutils
LOCAL_LDLIBS := -llog
LOCAL_MODULE := liblive555
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
LOCAL_CPPFLAGS := \
-DNULL=0 -DSOCKLEN_T=socklen_t -DNO_SSTREAM -DBSD=1 -DNO_SSTREAM -fexceptions -DANDROID
LOCAL_C_INCLUDES := \
$(LOCAL_PATH) \
$(LOCAL_PATH)/BasicUsageEnvironment/include \
$(LOCAL_PATH)/UsageEnvironment/include \
$(LOCAL_PATH)/groupsock/include \
$(LOCAL_PATH)/liveMedia/include
LOCAL_MODULE_TAGS := optional
#include $(BUILD_SHARED_LIBRARY)
include $(BUILD_STATIC_LIBRARY)
方案II
在live555的四个模块中分别写Android.mk编译脚本生成静态库,然后生成一个liblive555.so的动态库!
在live555源码下的Android.mk
live555/Android.mk
---------------------------------------------------------------------------------------------------------------
[html] view plaincopy
01.LOCAL_PATH := $(call my-dir)
02.
03.include $(CLEAR_VARS)
04.LOCAL_MODULE := live555
05.LOCAL_CFLAGS := -O2 -DSOCKLEN_T=socklen_t -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -fPIC -DPIC -DNO_SSTREAM=1 -DLOCALE_NOT_USED
-g -mthumb -mfloat-abi=softfp -fexceptions
06.#LOCAL_LDLIBS := -llog -lGLESv2
07.LOCAL_C_INCLUDES += $(LOCAL_PATH)/BasicUsageEnvironment/include $(LOCAL_PATH)/UsageEnvironment/include $(LOCAL_PATH)/groupsock/include
$(LOCAL_PATH)/liveMedia $(LOCAL_PATH)/liveMedia/include
08.LOCAL_STATIC_LIBRARIES := libliveMedia libBasicUsageEnvironment libUsageEnvironment libgroupsock libsupc++
09.LOCAL_SHARED_LIBRARIES := libcutils libstdc++ libc
10.
11.LOCAL_MODULE_TAGS := optional
12.
13.include $(BUILD_SHARED_LIBRARY)
14.
15.include $(call all-makefiles-under,$(LOCAL_PATH))
---------------------------------------------------------------------------------------------------------------
#live555源码liveMedia模块下的Android.mk
----------------------------------------------------------------------------------------------------------------
[html] view plaincopy
01.LOCAL_PATH := $(call my-dir)
02.
03.include $(CLEAR_VARS)
04.
05.LOCAL_CFLAGS := -O2 -DSOCKLEN_T=socklen_t -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -fPIC -DPIC -DNO_SSTREAM=1 -DLOCALE_NOT_USED -g
-mthumb -mfloat-abi=softfp -fexceptions
06.LOCAL_SRC_FILES := \
07. our_md5.c \
08. our_md5hl.c \
09. rtcp_from_spec.c \
10. AC3AudioRTPSink.cpp \
11. AC3AudioRTPSource.cpp \
12. AC3AudioStreamFramer.cpp \
13. ADTSAudioFileServerMediaSubsession.cpp \
14. ADTSAudioFileSource.cpp \
15. AMRAudioFileServerMediaSubsession.cpp \
16. AMRAudioFileSink.cpp \
17. AMRAudioFileSource.cpp \
18. AMRAudioRTPSink.cpp \
19. AMRAudioRTPSource.cpp \
20. AMRAudioSource.cpp \
21. AudioInputDevice.cpp \
22. AudioRTPSink.cpp \
23. AVIFileSink.cpp \
24. Base64.cpp \
25. BasicUDPSink.cpp \
26. BasicUDPSource.cpp \
27. BitVector.cpp \
28. ByteStreamFileSource.cpp \
29. ByteStreamMultiFileSource.cpp \
30. DarwinInjector.cpp \
31. DeviceSource.cpp \
32. DigestAuthentication.cpp \
33. DVVideoFileServerMediaSubsession.cpp \
34. DVVideoRTPSink.cpp \
35. DVVideoRTPSource.cpp \
36. DVVideoStreamFramer.cpp \
37. FileServerMediaSubsession.cpp \
38. FileSink.cpp \
39. FramedFileSource.cpp \
40. FramedFilter.cpp \
41. FramedSource.cpp \
42. GSMAudioRTPSink.cpp \
43. H261VideoRTPSource.cpp \
44. H263plusVideoFileServerMediaSubsession.cpp \
45. H263plusVideoRTPSink.cpp \
46. H263plusVideoRTPSource.cpp \
47. H263plusVideoStreamFramer.cpp \
48. H263plusVideoStreamParser.cpp \
49. H264VideoFileServerMediaSubsession.cpp \
50. H264VideoFileSink.cpp \
51. H264VideoRTPSink.cpp \
52. H264VideoRTPSource.cpp \
53. H264VideoStreamDiscreteFramer.cpp \
54. H264VideoStreamFramer.cpp \
55. InputFile.cpp \
56. JPEGVideoRTPSink.cpp \
57. JPEGVideoRTPSource.cpp \
58. JPEGVideoSource.cpp \
59. Locale.cpp \
60. Media.cpp \
61. MediaSession.cpp \
62. MediaSink.cpp \
63. MediaSource.cpp \
64. MP3ADU.cpp \
65. MP3ADUdescriptor.cpp \
66. MP3ADUinterleaving.cpp \
67. MP3ADURTPSink.cpp \
68. MP3ADURTPSource.cpp \
69. MP3ADUTranscoder.cpp \
70. MP3AudioFileServerMediaSubsession.cpp \
71. MP3FileSource.cpp \
72. MP3Internals.cpp \
73. MP3InternalsHuffman.cpp \
74. MP3InternalsHuffmanTable.cpp \
75. MP3StreamState.cpp \
76. MP3Transcoder.cpp \
77. MPEG1or2AudioRTPSink.cpp \
78. MPEG1or2AudioRTPSource.cpp \
79. MPEG1or2AudioStreamFramer.cpp \
80. MPEG1or2Demux.cpp \
81. MPEG1or2DemuxedElementaryStream.cpp \
82. MPEG1or2DemuxedServerMediaSubsession.cpp \
83. MPEG1or2FileServerDemux.cpp \
84. MPEG1or2VideoFileServerMediaSubsession.cpp \
85. MPEG1or2VideoRTPSink.cpp \
86. MPEG1or2VideoRTPSource.cpp \
87. MPEG1or2VideoStreamDiscreteFramer.cpp \
88. MPEG1or2VideoStreamFramer.cpp \
89. MPEG2IndexFromTransportStream.cpp \
90. MPEG2TransportFileServerMediaSubsession.cpp \
91. MPEG2TransportStreamFramer.cpp \
92. MPEG2TransportStreamFromESSource.cpp \
93. MPEG2TransportStreamFromPESSource.cpp \
94. MPEG2TransportStreamIndexFile.cpp \
95. MPEG2TransportStreamMultiplexor.cpp \
96. MPEG2TransportStreamTrickModeFilter.cpp \
97. MPEG4ESVideoRTPSink.cpp \
98. MPEG4ESVideoRTPSource.cpp \
99. MPEG4GenericRTPSink.cpp \
100. MPEG4GenericRTPSource.cpp \
101. MPEG4LATMAudioRTPSink.cpp \
102. MPEG4LATMAudioRTPSource.cpp \
103. MPEG4VideoFileServerMediaSubsession.cpp \
104. MPEG4VideoStreamDiscreteFramer.cpp \
105. MPEG4VideoStreamFramer.cpp \
106. MPEGVideoStreamFramer.cpp \
107. MPEGVideoStreamParser.cpp \
108. MultiFramedRTPSink.cpp \
109. MultiFramedRTPSource.cpp \
110. OnDemandServerMediaSubsession.cpp \
111. OutputFile.cpp \
112. PassiveServerMediaSubsession.cpp \
113. QCELPAudioRTPSource.cpp \
114. QuickTimeFileSink.cpp \
115. QuickTimeGenericRTPSource.cpp \
116. RTCP.cpp \
117. RTPInterface.cpp \
118. RTPSink.cpp \
119. RTPSource.cpp \
120. RTSPClient.cpp \
121. RTSPCommon.cpp \
122. RTSPServer.cpp \
123. ServerMediaSession.cpp \
124. SimpleRTPSink.cpp \
125. SimpleRTPSource.cpp \
126. SIPClient.cpp \
127. StreamParser.cpp \
128. uLawAudioFilter.cpp \
129. VideoRTPSink.cpp \
130. WAVAudioFileServerMediaSubsession.cpp \
131. WAVAudioFileSource.cpp \
132.
133.LOCAL_C_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)/include $(LOCAL_PATH)/../UsageEnvironment/include $(LOCAL_PATH)/../groupsock/include
134.
135.LOCAL_MODULE := libliveMedia
136.
137.include $(BUILD_STATIC_LIBRARY)
----------------------------------------------------------------------------------------------------------------
#在live555源码BasicUsageEnvironment模块下的Android.mk
----------------------------------------------------------------------------------------------------------------
[html] view plaincopy
01.LOCAL_MODULE_TAGS := optional
02.LOCAL_PATH := $(call my-dir)
03.
04.include $(CLEAR_VARS)
05.
06.LOCAL_CFLAGS := -O2 -DSOCKLEN_T=socklen_t -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -fPIC -DPIC -DNO_SSTREAM=1 -DLOCALE_NOT_USED -g
-mthumb -mfloat-abi=softfp -fexceptions
07.LOCAL_SRC_FILES := \
08. BasicHashTable.cpp \
09. BasicTaskScheduler0.cpp \
10. BasicTaskScheduler.cpp \
11. BasicUsageEnvironment0.cpp \
12. BasicUsageEnvironment.cpp \
13. DelayQueue.cpp
14.LOCAL_C_INCLUDES += $(LOCAL_PATH)/include $(LOCAL_PATH)/../UsageEnvironment/include $(LOCAL_PATH)/../groupsock/include
15.
16.LOCAL_MODULE := libBasicUsageEnvironment
17.
18.include $(BUILD_STATIC_LIBRARY)
----------------------------------------------------------------------------------------------------------------
#在live555源码groupsock模块下的Android.mk代码
----------------------------------------------------------------------------------------------------------------
[html] view plaincopy
01.LOCAL_PATH := $(call my-dir)
02.
03.include $(CLEAR_VARS)
04.
05.LOCAL_CFLAGS := -O2 -DSOCKLEN_T=socklen_t -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -fPIC -DPIC -DNO_SSTREAM=1 -DLOCALE_NOT_USED -g
-mthumb -mfloat-abi=softfp -fexceptions
06.LOCAL_SRC_FILES := \
07. GroupEId.cpp \
08. Groupsock.cpp \
09. GroupsockHelper.cpp \
10. inet.c \
11. IOHandlers.cpp \
12. NetAddress.cpp \
13. NetInterface.cpp
14.
15.LOCAL_C_INCLUDES += $(LOCAL_PATH)/include $(LOCAL_PATH)/../UsageEnvironment/include $(LOCAL_PATH)/../groupsock/include
16.
17.LOCAL_MODULE := libgroupsock
18.
19.include $(BUILD_STATIC_LIBRARY)
----------------------------------------------------------------------------------------------------------------
#在live555源码的UsageEnvironment模块下的Android.mk代码
-----------------------------------------------------------------------------------------------------------------
[html] view plaincopy
01.LOCAL_PATH := $(call my-dir)
02.
03.include $(CLEAR_VARS)
04.
05.LOCAL_CFLAGS := -O2 -DSOCKLEN_T=socklen_t -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -fPIC -DPIC -DNO_SSTREAM=1 -DLOCALE_NOT_USED -g
-mthumb -mfloat-abi=softfp -fexceptions
06.LOCAL_SRC_FILES := \
07. HashTable.cpp \
08. strDup.cpp \
09. UsageEnvironment.cpp
10.LOCAL_C_INCLUDES += $(LOCAL_PATH)/include $(LOCAL_PATH)/../UsageEnvironment/include $(LOCAL_PATH)/../groupsock/include
11.
12.LOCAL_MODULE := libUsageEnvironment
13.
14.include $(BUILD_STATIC_LIBRARY)
-----------------------------------------------------------------------------------------------------------------
#在jni同级目录下的Android.mk
------------------------------------------------------------------------------------------------------------------
[html] view plaincopy
01.include $(all-subdir-makefiles)
02.
------------------------------------------------------------------------------------------------------------------
然后在NDK编译就会生成四个模块的静态库和liblive555的动态库!
注:参考文档
http://hi.baidu.com/yunlongchn/item/6de3a7f6cf01c115ff358204