Darwin是Apple公司的开源视频服务器,支持通过编写Module来进行扩展,从而支持新的流媒体封装格式。本文给出如何编写支持新的流媒体封装格式的Module。
函数中标为红色部分的ModuleNameDispatch是Module中必须定义的另一个函数的名字,这个函数通常会是下面的样子:
编写模块就是根据要实现的功能,注册实现一系列的Role。为了编写一个支持特定封装格式的模块,如上代码所示,注册并实现了QTSS_Register_Role、QTSS_Initialize_Role、QTSS_RTSPPreProcessor_Role、QTSS_RTPSendPackets_Role、QTSS_ClientSessionClosing_Role等Role。接下来重点介绍QTSS_Register_Role、QTSS_RTSPPreProcessor_Role、QTSS_RTPSendPackets_Role。
Register Role是每个Module都必须实现的,且不需要注册。在这个Role中Module通过调用函数QTSS_AddRole注册所支持的其它Role。如下是典型的对应于Register Role的处理的实现,这里注册了三个Role,分别是QTSS_Initialize_Role、QTSS_RTSPPreProcessor_Role和QTSS_ClientSessionClosing_Role。
QTSS_RTSPPreProcessor_Role这个Role对应RTSP协议处理,可以参见《Darwin中RTSP协议的实现》了解Darwin视频服务器对于RTSP协议处理的细节,如下是一个典型的对应于QTSS_RTSPPreProcessor_Role的处理的实现。
理解这段代码需要理解Darwin中Object的概念,可以参照《Dictionary数据类型在Darwin视频服务器中的使用》,或者Darwin的文档《QuickTime Streaming Server Modules Programming Guide》。
每个RTSPRequest有一个名字为qtssRequestMethod的属性,其值与RTSP协议的请求方法对应,入Describe,Setup等。在与QTSS_RTSPPreProcessor_Role对应的处理中,对Describe等方法分别调用对应的函数进行处理。
注册了RTSP Prerequest Role或者RTSP Request Role的模块必须实现RTP Send Packets Role,模块通过该Role向发出请求的客户端发送流媒体数据。当需要向请求客户端发送流媒体数据的时候,注册了RTSP Prerequest Role或者RTSP Request Role的模块调用QTSS_Play,然后服务器就会通过RTP Send Packets Role调用该模块。注册了RTSP Prerequest Role或者RTSP Request Role的模块默认具有RTP Send Packets Role,不需要进行注册。
对应于QTSS_RTPSendPackets_Role的处理函数要实现的就是把流媒体数据按照实际播放的速度进行发送。这里的关键就是对发送速度的计算和把控。具体的实现是通过计算流媒体包的发送时间,得出如下数据结构中的具体数据,要发送的数据包、发送时间等。
Darwin的Module必须实现两个函数,其中一个在服务器加载Module的时候被调用,这个函数的名字必须是ModuleName_Main,其中ModuleName就是模块的名字,如果采用动态模块,编译后的模块文件名也必须是这个名字。这个函数的定义通常是下面的样子:
QTSS_Error ModuleName_Main(void* inPrivateArgs)
{
return _stublibrary_main(inPrivateArgs, ModuleNameDispatch);
}
函数中标为红色部分的ModuleNameDispatch是Module中必须定义的另一个函数的名字,这个函数通常会是下面的样子:
QTSS_Error ModuleNameDispatch (QTSS_Role inRole, QTSS_RoleParamPtr inParamBlock)
{
switch (inRole) {
case QTSS_Register_Role:
return Register (&inParamBlock->regParams);
case QTSS_Initialize_Role:
return Initialize (&inParamBlock->initParams);
case QTSS_RTSPPreProcessor_Role:
return ProcessRTSPRequest (&inParamBlock->rtspRequestParams);
case QTSS_RTPSendPackets_Role:
return SendPackets(&inParamBlock->rtpSendPacketsParams);
case QTSS_ClientSessionClosing_Role:
return DestroySession (&inParamBlock->clientSessionClosingParams);
}
return QTSS_NoErr;
}
编写模块就是根据要实现的功能,注册实现一系列的Role。为了编写一个支持特定封装格式的模块,如上代码所示,注册并实现了QTSS_Register_Role、QTSS_Initialize_Role、QTSS_RTSPPreProcessor_Role、QTSS_RTPSendPackets_Role、QTSS_ClientSessionClosing_Role等Role。接下来重点介绍QTSS_Register_Role、QTSS_RTSPPreProcessor_Role、QTSS_RTPSendPackets_Role。
Register Role是每个Module都必须实现的,且不需要注册。在这个Role中Module通过调用函数QTSS_AddRole注册所支持的其它Role。如下是典型的对应于Register Role的处理的实现,这里注册了三个Role,分别是QTSS_Initialize_Role、QTSS_RTSPPreProcessor_Role和QTSS_ClientSessionClosing_Role。
QTSS_Error Register (QTSS_Register_Params* inParams)
{
(void)QTSS_AddRole(QTSS_Initialize_Role);
(void)QTSS_AddRole(QTSS_RTSPPreProcessor_Role);
(void)QTSS_AddRole(QTSS_ClientSessionClosing_Role);
}
QTSS_RTSPPreProcessor_Role这个Role对应RTSP协议处理,可以参见《Darwin中RTSP协议的实现》了解Darwin视频服务器对于RTSP协议处理的细节,如下是一个典型的对应于QTSS_RTSPPreProcessor_Role的处理的实现。
QTSS_Error ProcessRTSPRequest(QTSS_StandardRTSP_Params* inParamBlock)
{
QTSS_RTSPMethod* theMethod = NULL;
UInt32 theMethodLen = 0;
if ((QTSS_GetValuePtr(inParamBlock->inRTSPRequest,
qtssRTSPReqMethod,
0,
(void**)&theMethod,
&theMethodLen) != QTSS_NoErr) ||
(theMethodLen != sizeof(QTSS_RTSPMethod))) {
return QTSS_RequestFailed;
}
QTSS_Error err = QTSS_NoErr;
switch (*theMethod) {
case qtssDescribeMethod:
err = DoDescribe(inParamBlock);
break;
case qtssSetupMethod:
err = DoSetup(inParamBlock);
break;
case qtssPlayMethod:
err = DoPlay(inParamBlock);
break;
case qtssTeardownMethod:
(void)QTSS_Teardown(inParamBlock->inClientSession);
(void)QTSS_SendStandardRTSPResponse(inParamBlock->inRTSPRequest, inParamBlock->inClientSession, 0);
break;
case qtssPauseMethod:
err = DoPause (inParamBlock);
break;
case qtssGetParameterMethod:
err = DoGetParameterMethod (inParamBlock);
break;
default:
break;
}
if (err != QTSS_NoErr)
(void)QTSS_Teardown(inParamBlock->inClientSession);
return QTSS_NoErr;
}
理解这段代码需要理解Darwin中Object的概念,可以参照《Dictionary数据类型在Darwin视频服务器中的使用》,或者Darwin的文档《QuickTime Streaming Server Modules Programming Guide》。
每个RTSPRequest有一个名字为qtssRequestMethod的属性,其值与RTSP协议的请求方法对应,入Describe,Setup等。在与QTSS_RTSPPreProcessor_Role对应的处理中,对Describe等方法分别调用对应的函数进行处理。
注册了RTSP Prerequest Role或者RTSP Request Role的模块必须实现RTP Send Packets Role,模块通过该Role向发出请求的客户端发送流媒体数据。当需要向请求客户端发送流媒体数据的时候,注册了RTSP Prerequest Role或者RTSP Request Role的模块调用QTSS_Play,然后服务器就会通过RTP Send Packets Role调用该模块。注册了RTSP Prerequest Role或者RTSP Request Role的模块默认具有RTP Send Packets Role,不需要进行注册。
对应于QTSS_RTPSendPackets_Role的处理函数要实现的就是把流媒体数据按照实际播放的速度进行发送。这里的关键就是对发送速度的计算和把控。具体的实现是通过计算流媒体包的发送时间,得出如下数据结构中的具体数据,要发送的数据包、发送时间等。
typedef struct
{
void* packetData;
QTSS_TimeVal packetTransmitTime;
QTSS_TimeVal suggestedWakeupTime;
} QTSS_PacketStruct;
QTSS_Error SendPackets(QTSS_RTPSendPackets_Params* inParams)
{
...
while (true) { // send packets loop
if (fPacket.packetData == NULL) {
theTransmitTime = GetNextPacket ();
fPacket.packetTransmitTime = theTransmitTime;
theReturn = QTSS_Write(theStream, &fPacket .....);
if (theReturn == QTSS_WouldBlock) {
return;
else { //发送成功
fPacket.packetData = NULL;
}
}
}
}