2. EMIPLIB的消息机制
EMIPLIB组件对象间,采用消息(Message)驱动机制实现数据的交流与互通。换句话说,组件间数据的交互,只能依靠消息的传递实现。
依据本节第一部分描述的“EMIPLIB的功能模块划分”,将组件分为不同功能类别,对应的,也将消息划分为不同种类,只有相同或者相近功能的组件间才共享同一定义的消息。具体的系统消息结构见下图所示:
EMIPLIB消息结构图
所有消息均继承自基类MIPMessage,用以定义消息类的基本结构。每个消息必须带有两个关键属性:Type(类型)和Subtype(子类型)。其中Type字段已在MIPMessage中定义,用以标识该消息所属功能模块,Subtype则留给继承类以细分消息类别。大致如下所示(◆表示Subtype):
(1) MIPMESSAGE_TYPE_SYSTEM:系统消息,对应上图所示的MIPSystemMessage类。
u MIPSYSTEMMESSAGE_TYPE_WAITTIME:有组件链下发给系统的第一个组件(一般为定时器),表示延时设定时间后再触发下一组件。
u MIPSYSTEMMESSAGE_TYPE_ISTIME:触发下一组件的消息子类型。
(2) MIPMESSAGE_TYPE_AUDIO_RAW
对应MIPRawFloatAudioMessage类:
u MIPRAWAUDIOMESSAGE_TYPE_FLOAT
对应MIPRawU8AudioMessage类:
u MIPRAWAUDIOMESSAGE_TYPE_U8
对应MIPRaw16bitAudioMessage类:
u MIPRAWAUDIOMESSAGE_TYPE_U16LE
u MIPRAWAUDIOMESSAGE_TYPE_U16BE
u MIPRAWAUDIOMESSAGE_TYPE_S16LE
u MIPRAWAUDIOMESSAGE_TYPE_S16BE
u MIPRAWAUDIOMESSAGE_TYPE_S16
MIPRAWAUDIOMESSAGE_TYPE_U16
(3) MIPMESSAGE_TYPE_AUDIO_ENCODED:对应MIPEncodedAudioMessage类,通过在该类中定义如下子类型(并未分别为每个子类型单独实现类)
u MIPENCODEDAUDIOMESSAGE_TYPE_SPEEX
u MIPENCODEDAUDIOMESSAGE_TYPE_ULAW
u MIPENCODEDAUDIOMESSAGE_TYPE_ALAW
u MIPENCODEDAUDIOMESSAGE_TYPE_GSM
u MIPENCODEDAUDIOMESSAGE_TYPE_LPC
u MIPENCODEDAUDIOMESSAGE_TYPE_SILK
(4) MIPMESSAGE_TYPE_VIDEO_RAW:实现继承自MIPVideoMessage
对应MIPRawYUV420PVideoMessage类:
u MIPRAWVIDEOMESSAGE_TYPE_YUV420P
对应MIPRawYUYVVideoMessage类:
u MIPRAWVIDEOMESSAGE_TYPE_YUYV
对应MIPRawRGBVideoMessage类
u MIPRAWVIDEOMESSAGE_TYPE_RGB24
u MIPRAWVIDEOMESSAGE_TYPE_RGB32
(5) MIPMESSAGE_TYPE_VIDEO_ENCODED:对应MIPEncodedVideoMessage类
u MIPENCODEDVIDEOMESSAGE_TYPE_H263P
u MIPENCODEDVIDEOMESSAGE_TYPE_JPEG
(6) MIPMESSAGE_TYPE_RTP
u MIPRTPMESSAGE_TYPE_SEND:对应MIPRTPSendMessage类。
u MIPRTPMESSAGE_TYPE_RECEIVE:对应MIPRTPReceiveMessage类。
(7) MIPMESSAGE_TYPE_ALL:特别的,用于消息过滤机制,表示此组件接受任何形式的消息。
注:为了实现的方面,EMIPLIB为RAW Audio/Video(原始数据流)所定义的子类型采用部分合并的方式,将结构类似的子类型重用,异构的子类型则分别实现。为Encoded Audio/Video(编码数据流)所定义的子类型由于结构一致,重用一个实现类即可。
3. EMIPLIB的RTP打包、解包机制
EMIPLIB的RTP打包与解包机制并没有采用相同的可逆设计,还挺有意思的,故此处提出来专门说明。
(1) RTP打包机制
上文已经说明,EMIPLIB的基本单位是组件(Component),整个流程的实现,是基于一条Component Chain将组件串起来。因此,RTP打包模块也是按照此思路完成。
RTP部分的组件链如下图所示:
输出RTP码流的组件链连接图
下面针对上图RTP部分简要说明。
u 按照编码格式打包为对应RTP包:通过定义RTP编码的基类MIPRTPEncoder(继承自MIPComponent,作为组件实现) ,不同编码格式可以有自己的实现方案,但均需继承此基类并以此来描述自己所提供的服务 。下图所示为基类与继承类间的关系。
RTP打包模块结构图
值得一提的是,MIPRTPH263Encoder作为H.263+的RFC实现,而MIPRTPVIdeoEncoder则作为H.263+与YUV420P的内部实现方案,不能在有外部RTP依赖关系的系统环境中使用。之所以将YUV420P作为内部实现,推测是因为RFC中并未定义未被压缩的原始码流的RTP实现方案。
u RTP统一配置与报文发送:由MIPRTPComponent类整合JRTPLIB实现。MIPRTPComponent类可以实现RTP报文的发送与接收。通过设置RTPSession参数,统一配置外发RTP报文的IP地址及端口号、时间戳、收发方缓存、最大报文长度等基本参数。
(2) RTP解包机制
RTP的解包机制则有所不同。
u RTP报文接收:仍然使用发包处所使用的MIPRTPComponent实现,但配置信息通过SIP交互的初始化信息自动下发。
RTP码流接收的组件链结构图
u 按照格式解包:并不是类似Encoder的方式,通过继承MIPRTPVIdeoEncoder父类的方式实现。而是格外的定义了非组件形式的MIPRTPPacketDecoder纯虚类,统一描述不同负载形式的RTP报文解码所需要提供的服务。每种具体格式的报文解包实现都需要继承这个纯虚类。
当接收方处理多种负载类型的RTP报文时,由MIPRTPVIdeoDecoder作为全局控制中心,将报文发送到对应解码实现中。这样做的好处是,系统可以同时处理多种格式的RTP报文且不会冲突。
解包模块结构图
MIPRTPVIdeoDecoder中负载类型与RTP解码实现类的映射关系通过一个数组来实现。根据系统当前所需要的解码组件动态加载。在RTP的RFC文献中,某些数据格式类型绑定确定的负载类型编号,有些则可以通过临时的动态绑定操作,将某个预留的负载类型编号绑定某个特定实现。具体的实现是通过RTP传输前的SIP报文携带的SDP包体信息完成交互的。
三‑8接收RTP时组件关系图
当然,EMIPLIB仅仅是流媒体系统的框架,其中有许多功能尚未实现,需要开发者根据自己的需要添加,比如:
(1) 针对H.264与MPEG4编码的RTP报文打包;
(2) 前端回送的码流打包为容器格式保存;
(3) 与其他SIP应用程序的交互(初始化、暂停、回放等等)
EMIPLIB的可扩展性良好,在理解上述架构的基础上,可以方便的添加组件实现。(1)(2)已经的源代码我已经写好了,(3)还在写,但开发难度不大,等我有空再注释下,传上来 嘿嘿~
PS:为嘛我老稀饭写系列哩,完全在给自己刨坟。。。
再PS:这图片,传的我抑郁
再PS:之前“EMIPLIB消息结构图”传晕了 弄错了 多谢转载的不知道谁指出来啦~~谢谢哦 已经改正啦