当前位置:首页 > darwin分析
QTSSModule* theReflectorModule = new QTSSModule(\);
(void)theReflectorModule->SetupModule(&sCallbacks, &QTSSReflectorModule_Main); 调用 QTSSReflectorModule_Main函数, 将fDispatchFunc设置为 thePrivateArgs.outDispatchFunction(QTSSReflectorModuleDispatch),fDispatchFunc为 QTSSModule的私有类成员。这样DSS可以通过具体模块的基类QTSSModule的这个私有成员来 让具体模块进行分发处理。 调用QTSServerInterface::LogError函数进行log功能
x++)
for(UInt32 x=0;x QTSServerInterface::GetModule(QTSSModule::kErrorLogRole,x)- >CallDispatch(QTSS_ErrorLog_Role,&theParams); // 因为只有QTSSErrorLogModule注册kErrorLogRole,实际上会调用这个类的 // LogError函数。 If this is a fatal error, 调用SetValue set the proper attribute in the RTSPServer dictionary。 (void)AddModule(theReflectorModule); 后面同上面所说的QTSSErrorLogModule加载情况。 ? 一些模块的介绍 一、QTSSRTPFileModule Content source module that uses the QTFileLib to serve Hinted QuickTime files to clients. 支持TSS_Initialize_Role、QTSS_RTSPPreProcessor_Role、QTSS_ClientSessionClosing_Role、 QTSS_RereadPrefs_Role。Dispatch函数里也提供了QTSS_RTPSendPackets_Role的处理,直接通过模块来调用这个Role的处理。 在initialize函数里,通过SetupSupportedMethods登记支持的方法:DESCRIBE, SETUP, PLAY, PAUSE, and TEARDOWN。 !!这个模块并没有被加载!! (1)、ProcessRTSPRequest QTSS_RTSPPreProcessor_Role的处理函数。 根据请求内容,分别做出处理: Describe: DoDescribe(inParams); Setup: DoSetup(inParams); Play: DoPlay(inParams); Teardown: // Tell the server that this session should be killed, and send a TEARDOWN response QTSS_Teardown(...); QTSS_SendStandardRTSPResponse(); Pause: QTSS_Pause(); QTSS_SendStandardRTSPResponse(); (2)、DoDescribe Check and see if this is a request we should handle. We handle all requests with URLs that end in a '.rtp' Get the FileSession for this DESCRIBE, if any. if(theFile != NULL) { // There is already a file for this session. This can happen if there are multiple // DESCRIBES, or a DESCRIBE has been issued with a Session ID, or some such thing. if ( !theFullPath.Equal( *theFile->fFile.GetMoviePath() ) ) { delete theFile; theFile = NULL; QTSS_SetValue(inParamBlock->inClientSession, sFileSessionAttr, 0, &theFile, sizeof(theFile)); } } if(theFile == NULL) { // 创建FileSession类对象,调用theFile->fFile.Initialize(theFullPath, 8); CreateRTPFileSession(inParamBlock, theFullPath, &theFile); QTSS_SetValue(inParamBlock->inClientSession, sFileSessionAttr, 0, &theFile, sizeof(theFile)); } 二、QTSSFileModule模块 Content source module that uses the QTFileLib to serve Hinted QuickTime files to clients. 注册了QTSS_Initialize_Role、QTSS_RTSPRequest_Role、QTSS_ClientSessionClosing_Role、 QTSS_RereadPrefs_Role的处理。在Dispatch函数里还添加了QTSS_RTPSendPackets_Role的处理。 在initialize函数里,通过SetupSupportedMethods登记支持的方法:DESCRIBE, SETUP, PLAY, PAUSE, and TEARDOWN。 (1)、ProcessRTSPRequest() QTSS_RTSPRequest_Role的处理函数。 根据请求内容,分别做出处理: Describe: DoDescribe(inParams); Setup: DoSetup(inParams); Play: DoPlay(inParams); Teardown: // Tell the server that this session should be killed, and send a TEARDOWN response QTSS_Teardown(...); QTSS_SendStandardRTSPResponse(); Pause: QTSS_Pause(); QTSS_SendStandardRTSPResponse(); (2)、DoDescribe() if(isSDP(inParamBlock)) // sdp file { ... ... QTSS_GetValuePtr(inParamBlock->inRTSPRequest, qtssRTSPReqFilePath, 0,(void**)&pathStr.Ptr, &pathStr.Len); QTSSModuleUtils::SendErrorResponse(inParamBlock->inRTSPRequest,qtssClientNotFound,sNoSDPFileFoundErr,&pathStr); ... ... return err; } ... ... if (theFile != NULL) { // There is already a file for this session. This can happen if there are multiple // DESCRIBES, or a DESCRIBE has been issued with a Session ID, or some such thing. moviePath(theFile->fFile.GetMoviePath()); if(!requestPath.Equal(moviePath)) { DeleteFileSession(theFile); theFile = NULL; QTSS_SetValue(inParamBlock->inClientSession, sFileSessionAttr, 0, &theFile, sizeof(theFile)); } } if (theFile == NULL) { // 创建FileSession类对象,调用theFile->fFile.Initialize(inPath,); // theFile->fFile为QTRTPFile类型的对象。 // 通过QTRTPFile、QTFile、QTSSFile等类对象来完成媒体文件的解析 CreateQTRTPFile(inParamBlock, thePath.GetObject(), &theFile); QTSS_SetValue(inParamBlock->inClientSession, sFileSessionAttr, 0, &theFile, sizeof(theFile)); } // replace the sacred character we have trodden on in order to truncate the path. // 文件名添加.sdp后缀 thePath.GetObject()[thePathLen – sSDPSuffix.Len] = sSDPSuffix.Ptr[0]; if (sEnableMovieFileSDP) // 在配置文件里enable_movie_file_sdp为false,为什么也能在客 // 户端的播放器里访问sdp文件??? { // Check to see if there is an sdp file, if so, return that file instead of the // built-in sdp. QTSSModuleUtils::ReadEntireFile(thePath.GetObject(), &theSDPData); } 后续是sdp信息的处理(这里实现什么???)如果配置文件中的record_movie_file_sdp为 true,则会生成一个sdp文件。 // now parse the movie media sdp data. We need to do this in order to extract payload // information. The SDP parser object will not take responsibility of the memory (one // exception... see above) // 注意在前面已经调用了: // theSDPData.Ptr = theFile->fFile.GetSDPFile(&sdpLen); theSDPData.Len = sdpLen; // 从媒体文件里获取sdp信息。 theFile->fSDPSource.Parse(theSDPData.Ptr, theSDPData.Len); (3)、DoSetup() if (isSDP(inParamBlock)) { ... ... } QTSS_GetValue(inParamBlock->inClientSession, sFileSessionAttr, 0, (void*)&theFile, &theLen); if((theErr != QTSS_NoErr) || (theLen != sizeof(FileSession*))) { ... ... } QTSS_GetValueAsString(inParamBlock->inRTSPRequest, qtssRTSPReqFileDigit, 0, &theDigitStr); // 比如客户端发送一个 //“SETUP rtsp://192.168.2.163:554/sample_100kbit.mp4/trackID=3 RTSP/1.0\\r\\n”请求,则 // theTrackID等于3。 Uint32 theTrackID = ::strtol(theDigitStr, NULL, 10); // 调用QTRTPFile::AddTrack theFile->fFile.AddTrack(theTrackID, true); // Before setting up this track, check to see if there is an If-Modified-Since date. If // there is, and the content hasn't been modified, then just return a 304 Not Modified 这里所起的作用是什么??? // Find the payload for this track ID(if applicable) 根据theFile->fSDPSource的streaminfo,设置thePayload、thePayloadType、bufferDelay // Create a new RTP stream // 实际上是调用RTPSession::AddStream() QTSS_AddRTPStream(inParamBlock->inClientSession, inParamBlock->inRTSPRequest, &newStream, 0); // Set the payload type, payload name & timescale of this track // Set the number of quality levels. Allow up to 6 调用QTSS_SetValue进行设置。 // Get the SSRC of this track // give the file some info it needs. 根据TrackID,将对应的trackEntry->SSRC设置为上面获得的SSRC,将trackEntry->Cookie1 Cookie2 分别设为newStream、thePayloadType。 theErr = QTSS_GetValuePtr(inParamBlock->inRTSPHeaders, qtssXRTPMetaInfoHeader, 0, (void**)&theHeader.Ptr, &theHeader.Len); if(theErr == QTSS_NoErr) { ... ... } // Our array has now been updated to reflect the fields requested by the client. send the // setup response 调用QTSS_AppendRTSPHeader QTSS_SendStandardRTSPResponse(inParamBlock->inRTSPRequest, newStream, 0); (4)、SetupCacheBuffers() 通过QTSS_GetValue获取playCount值。 // increments num buffers after initialization so do only once per session // Allocate函数以及OSFileSource::ReadFromCache/ReadFromDisk函数的分析待续 if (sEnableSharedBuffers && playCount == 1) (*theFile)->fFile.AllocateSharedBuffers(sSharedBufferUnitKSize, sSharedBufferInc, sSharedBufferUnitSize,sSharedBufferMaxUnits); if (sEnablePrivateBuffers) // reinitializes buffers to current location so do every time (*theFile)->fFile.AllocatePrivateBuffers(sSharedBufferUnitKSize, sPrivateBufferUnitSize, sPrivateBufferMaxUnits); playCount ++; QTSS_SetValue(inParamBlock->inClientSession, sFileSessionPlayCountAttrID, 0, &playCount, (5)、DoPlay() if (isSDP(inParamBlock)) { ... ... } QTSS_GetValue(inParamBlock->inClientSession, sFileSessionAttr, 0, (void*)&theFile, &theLen); SetupCacheBuffers(inParamBlock, theFile); 调用一系列的设置工作QTSS_SetValue。。。 // Tell the server to start playing this movie. We do want it to send RTCP SRs, but we // DON'T want it to write the RTP header // 调用RTPSession::Play QTSS_Play(inParamBlock->inClientSession, inParamBlock->inRTSPRequest, qtssPlayFlagsSendRTCP); 准备RTSP回复内容,并调用QTSS_SendStandardRTSPResponse (6)、SendPackets() QTSS_RTPSendPackets_Role的处理函数,在RTPSession::Run函数里会调用这个Role的注册函数。 theLastPacketTrack = (*theFile)->fFile.GetLastPacketTrack(); while (true) { if ((*theFile)->fPacketStruct.packetData == NULL) { // 寻找要传输的包,theTransmitTime为发送时间 theTransmitTime = (*theFile)->fFile.GetNextPacket( (char**)&(*theFile)->fPacketStruct.packetData, &(*theFile)->fNextPacketLen); // 刚找到的 theLastPacketTrack = (*theFile)->fFile.GetLastPacketTrack(); theStream = (QTSS_Object)theLastPacketTrack->Cookie1; // Check to see if we should stop playing now if (((*theFile)->fStopTime !=-1) && (theTransmitTime > (*theFile)->fStopTime)) if (((*theFile)->fStopTrackID !=0) && ((*theFile)->fStopTrackID == theLastPacketTrack->TrackID) && (theLastPacketTrack->HTCB->fCurrentPacketNumber > (*theFile)->fStopPN)) { // We should indeed stop playing ... ... inParams->outNextPacketTime = qtssDontCallSendPacketsAgain; ... ... return QTSS_NoErr; } // Find out what our play speed is. Send packets out at the specified rate, // and do so by altering the transmit time of the packet based on the // Speed rate. 调整theTransmitTime } // 如果还没有数据 if ((*theFile)->fPacketStruct.packetData == NULL) { inParams->outNextPacketTime = qtssDontCallSendPacketsAgain; return QTSS_NoERR; } // 发送数据 // If the stream is video, we need to make sure that QTRTPFile knows what quality level // we're at 设置quality level。 adjust the timestamp so it reflects paused time. // 调用RTPStream::Write函数。RTPStream::Write返回EAGAIN时,QTSS_Write返回QTSS_WouldBlock theErr = QTSS_Write(theStream, &(*theFile)->fPacketStruct, (*theFile)->fNextPacketLen,NULL,theFlags); // 设置inParams->outNextPacketTime,RTPSession::Run函数根据outNextPacketTime,决定返回值。 if ( theErr == QTSS_WouldBlock ) { // reset the packet time stamp so we adjust it again when we really do send it if (currentTimeStamp != pauseTimeStamp) SetPacketTimeStamp(currentTimeStamp, packetDataPtr); // In the case of a QTSS_WouldBlock error, the packetTransmitTime field of the // packet struct will be set to the time to wakeup, or -1 if not known. // If the time to wakeup is not given by the server, just give a fixed guess interval if ((*theFile)->fPacketStruct.suggestedWakeupTime == -1) inParams->outNextPacketTime = sFlowControlProbeInterval; else
共分享92篇相关文档